diff options
Diffstat (limited to '')
-rw-r--r-- | unotools/source/misc/ServiceDocumenter.cxx | 74 | ||||
-rw-r--r-- | unotools/source/misc/ServiceDocumenter.hxx | 51 | ||||
-rw-r--r-- | unotools/source/misc/ZipPackageHelper.cxx | 183 | ||||
-rw-r--r-- | unotools/source/misc/closeveto.cxx | 147 | ||||
-rw-r--r-- | unotools/source/misc/datetime.cxx | 525 | ||||
-rw-r--r-- | unotools/source/misc/defaultencoding.cxx | 33 | ||||
-rw-r--r-- | unotools/source/misc/desktopterminationobserver.cxx | 188 | ||||
-rw-r--r-- | unotools/source/misc/eventlisteneradapter.cxx | 155 | ||||
-rw-r--r-- | unotools/source/misc/fontcvt.cxx | 1443 | ||||
-rw-r--r-- | unotools/source/misc/fontdefs.cxx | 560 | ||||
-rw-r--r-- | unotools/source/misc/mediadescriptor.cxx | 766 | ||||
-rw-r--r-- | unotools/source/misc/sharedunocomponent.cxx | 199 | ||||
-rw-r--r-- | unotools/source/misc/syslocale.cxx | 222 | ||||
-rw-r--r-- | unotools/source/misc/unotoolsservices.cxx | 23 | ||||
-rw-r--r-- | unotools/source/misc/wincodepage.cxx | 138 |
15 files changed, 4707 insertions, 0 deletions
diff --git a/unotools/source/misc/ServiceDocumenter.cxx b/unotools/source/misc/ServiceDocumenter.cxx new file mode 100644 index 000000000..0823d2a66 --- /dev/null +++ b/unotools/source/misc/ServiceDocumenter.cxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#include "ServiceDocumenter.hxx" +#include <unotoolsservices.hxx> +#include <comphelper/servicedecl.hxx> +#include <com/sun/star/system/SystemShellExecuteFlags.hpp> +#include <com/sun/star/system/XSystemShellExecute.hpp> +using namespace com::sun::star; +using uno::Reference; +using lang::XServiceInfo; +using lang::XTypeProvider; + +void unotools::misc::ServiceDocumenter::showCoreDocs(const Reference<XServiceInfo>& xService) +{ + if(!xService.is()) + return; + auto xMSF(m_xContext->getServiceManager()); + Reference<system::XSystemShellExecute> xShell(xMSF->createInstanceWithContext("com.sun.star.system.SystemShellExecute", m_xContext), uno::UNO_QUERY); + xShell->execute( + m_sCoreBaseUrl + xService->getImplementationName() + ".html", "", + css::system::SystemShellExecuteFlags::URIS_ONLY); +} + +void unotools::misc::ServiceDocumenter::showInterfaceDocs(const Reference<XTypeProvider>& xTypeProvider) +{ + if(!xTypeProvider.is()) + return; + auto xMSF(m_xContext->getServiceManager()); + Reference<system::XSystemShellExecute> xShell(xMSF->createInstanceWithContext("com.sun.star.system.SystemShellExecute", m_xContext), uno::UNO_QUERY); + const css::uno::Sequence<css::uno::Type> aTypes = xTypeProvider->getTypes(); + for(const auto& aType : aTypes) + { + auto sUrl = aType.getTypeName(); + sal_Int32 nIdx = 0; + while(nIdx != -1) + sUrl = sUrl.replaceFirst(".", "_1_1", &nIdx); + xShell->execute( + m_sServiceBaseUrl + "/interface" + sUrl + ".html", "", + css::system::SystemShellExecuteFlags::URIS_ONLY); + } +} + +void unotools::misc::ServiceDocumenter::showServiceDocs(const Reference<XServiceInfo>& xService) +{ + if(!xService.is()) + return; + auto xMSF(m_xContext->getServiceManager()); + Reference<system::XSystemShellExecute> xShell(xMSF->createInstanceWithContext("com.sun.star.system.SystemShellExecute", m_xContext), uno::UNO_QUERY); + const css::uno::Sequence<OUString> aServiceNames = xService->getSupportedServiceNames(); + for(const auto& sService : aServiceNames) + { + auto sUrl = sService; + sal_Int32 nIdx = 0; + while(nIdx != -1) + sUrl = sUrl.replaceFirst(".", "_1_1", &nIdx); + xShell->execute( + m_sServiceBaseUrl + "/service" + sUrl + ".html", "", + css::system::SystemShellExecuteFlags::URIS_ONLY); + } +} + +namespace sdecl = ::comphelper::service_decl; +sdecl::class_< unotools::misc::ServiceDocumenter > const ServiceDocumenterImpl; +const sdecl::ServiceDecl ServiceDocumenterDecl( + ServiceDocumenterImpl, + "com.sun.star.comp.unotools.misc.ServiceDocumenter", + ""); + diff --git a/unotools/source/misc/ServiceDocumenter.hxx b/unotools/source/misc/ServiceDocumenter.hxx new file mode 100644 index 000000000..cad333ddb --- /dev/null +++ b/unotools/source/misc/ServiceDocumenter.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#ifndef INCLUDED_UNOTOOLS_INC_SERVICEDOCUMENTER_HXX +#define INCLUDED_UNOTOOLS_INC_SERVICEDOCUMENTER_HXX + +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/script/XServiceDocumenter.hpp> + +namespace com::sun::star::uno { class XComponentContext; } + +namespace unotools::misc { + +class ServiceDocumenter : public ::cppu::WeakImplHelper< + css::script::XServiceDocumenter> +{ + public: + ServiceDocumenter(css::uno::Reference< css::uno::XComponentContext> const& xContext) + : m_xContext(xContext) + , m_sCoreBaseUrl("http://example.com") + , m_sServiceBaseUrl("https://api.libreoffice.org/docs/idl/ref") + {}; + // XServiceDocumenter + virtual OUString SAL_CALL getCoreBaseUrl() override + { return m_sCoreBaseUrl; }; + virtual void SAL_CALL setCoreBaseUrl( const OUString& sCoreBaseUrl ) override + { m_sCoreBaseUrl = sCoreBaseUrl; }; + virtual OUString SAL_CALL getServiceBaseUrl() override + { return m_sServiceBaseUrl; }; + virtual void SAL_CALL setServiceBaseUrl( const OUString& sServiceBaseUrl ) override + { m_sServiceBaseUrl = sServiceBaseUrl; }; + virtual void SAL_CALL showServiceDocs( const ::css::uno::Reference< ::css::lang::XServiceInfo >& xService) override; + virtual void SAL_CALL showInterfaceDocs( const ::css::uno::Reference< ::css::lang::XTypeProvider >& xTypeProvider ) override; + virtual void SAL_CALL showCoreDocs( const ::css::uno::Reference< ::css::lang::XServiceInfo >& xService) override; + protected: + virtual ~ServiceDocumenter() override + {}; + private: + css::uno::Reference< css::uno::XComponentContext> m_xContext; + OUString m_sCoreBaseUrl; + OUString m_sServiceBaseUrl; +}; + +} +#endif +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/misc/ZipPackageHelper.cxx b/unotools/source/misc/ZipPackageHelper.cxx new file mode 100644 index 000000000..d690e3015 --- /dev/null +++ b/unotools/source/misc/ZipPackageHelper.cxx @@ -0,0 +1,183 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +#include <unotools/ZipPackageHelper.hxx> +#include <comphelper/storagehelper.hxx> +#include <osl/file.hxx> +#include <unotools/streamwrap.hxx> +#include <tools/stream.hxx> +#include <tools/urlobj.hxx> + +#include <rtl/uri.hxx> + +namespace com::sun::star::io { class XInputStream; } + +using namespace utl; +using namespace osl; +using namespace comphelper; +using namespace com::sun::star; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::util; +using namespace com::sun::star::container; +using namespace com::sun::star::beans; +using namespace com::sun::star::io; + +using ::rtl::Uri; + +ZipPackageHelper::ZipPackageHelper( + const Reference< XComponentContext >& rxContext, + const OUString& sPackageURL) +: mxContext( rxContext ), + mxHNameAccess(), + mxFactory(), + mxRootFolder() +{ + // create the package zip file + Sequence< Any > aArguments( 2 ); + aArguments[ 0 ] <<= sPackageURL; + + // let ZipPackage be used + beans::NamedValue aArg; + aArg.Name = "StorageFormat"; + aArg.Value <<= OUString(ZIP_STORAGE_FORMAT_STRING); + aArguments[ 1 ] <<= aArg; + + Reference< XHierarchicalNameAccess > xHNameAccess( + mxContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.packages.comp.ZipPackage", + aArguments, mxContext ), UNO_QUERY); + mxHNameAccess = xHNameAccess; + + if( !mxHNameAccess.is() ) + return; + + Reference<XSingleServiceFactory> xFactory(mxHNameAccess, UNO_QUERY); + mxFactory = xFactory; + + // get root zip folder + mxHNameAccess->getByHierarchicalName( "/" ) >>= mxRootFolder; +} + +static OUString encodeZipUri( const OUString& rURI ) +{ + return Uri::encode( rURI, rtl_UriCharClassUric, rtl_UriEncodeCheckEscapes, RTL_TEXTENCODING_UTF8 ); +} + +Reference< XInterface >& ZipPackageHelper::getRootFolder() +{ + return mxRootFolder; +} + +Reference< XInterface > ZipPackageHelper::addFolder( Reference< XInterface > const & xRootFolder, + const OUString& rName ) +{ + if ( rName == ".." || rName == "." ) + throw lang::IllegalArgumentException(); + + Sequence< Any > aArgs(1); + aArgs[0] <<= true; + + Reference< XInterface > xFolder( mxFactory->createInstanceWithArguments(aArgs) ); + Reference< XNamed > xNamed( xFolder, UNO_QUERY ); + Reference< XChild > xChild( xFolder, UNO_QUERY ); + + if( xNamed.is() && xChild.is() ) + { + OUString aName( encodeZipUri( rName ) ); + xNamed->setName( aName ); + xChild->setParent( xRootFolder ); + } + + return xFolder; +} + +void ZipPackageHelper::addFolderWithContent( Reference< XInterface > const & xRootFolder, const OUString& rDirURL ) +{ + if (rDirURL.isEmpty()) + return; + + osl::Directory aDirectory(rDirURL); + + if (aDirectory.open() != osl::FileBase::E_None) + return; + + osl::DirectoryItem aDirectoryItem; + + while (osl::FileBase::E_None == aDirectory.getNextItem(aDirectoryItem)) + { + osl::FileStatus aFileStatus(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL | osl_FileStatus_Mask_FileName); + + if (osl::FileBase::E_None == aDirectoryItem.getFileStatus(aFileStatus)) + { + if (aFileStatus.isDirectory()) + { + const OUString aFileName(aFileStatus.getFileName()); + + if (!aFileName.isEmpty()) + { + Reference<XInterface> folder(addFolder(xRootFolder, aFileName)); + addFolderWithContent(folder, aFileStatus.getFileURL()); + } + } + else if (aFileStatus.isRegular()) + { + addFile(xRootFolder, aFileStatus.getFileURL()); + } + } + } +} + +void ZipPackageHelper::addFile( css::uno::Reference< css::uno::XInterface > const & xRootFolder, + const OUString& rSourceFileURL ) +{ + INetURLObject aURL( rSourceFileURL ); + OUString aName( aURL.getName() ); + + SvFileStream* pStream = new SvFileStream(rSourceFileURL, StreamMode::READ ); + Reference< XInputStream > xInput( new utl::OSeekableInputStreamWrapper( pStream, true ) ); + Reference< XActiveDataSink > xSink( mxFactory->createInstance(), UNO_QUERY ); + Reference< XUnoTunnel > xTunnel( xSink, UNO_QUERY ); + if( !xSink.is() || !xTunnel.is()) + return; + + Reference< XNameContainer > xNameContainer(xRootFolder, UNO_QUERY ); + xNameContainer->insertByName(encodeZipUri( aName ), makeAny(xTunnel)); + xSink->setInputStream( xInput ); +} + +void ZipPackageHelper::savePackage() +{ + Reference< XChangesBatch > xBatch( mxHNameAccess, UNO_QUERY ); + if( xBatch.is() ) + xBatch->commitChanges(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/misc/closeveto.cxx b/unotools/source/misc/closeveto.cxx new file mode 100644 index 000000000..bf2cb8382 --- /dev/null +++ b/unotools/source/misc/closeveto.cxx @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <unotools/closeveto.hxx> + +#include <com/sun/star/util/CloseVetoException.hpp> +#include <com/sun/star/util/XCloseable.hpp> + +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> +#include <tools/diagnose_ex.h> + +namespace utl +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::util::XCloseable; + using ::com::sun::star::util::XCloseListener; + using ::com::sun::star::util::CloseVetoException; + using ::com::sun::star::lang::EventObject; + + //= CloseListener_Impl + + typedef ::cppu::WeakImplHelper < XCloseListener + > CloseListener_Base; + + namespace { + + class CloseListener_Impl : public CloseListener_Base + { + public: + explicit CloseListener_Impl(bool const bHasOwnership) + : m_bHasOwnership(bHasOwnership) + { + } + + // XCloseListener + virtual void SAL_CALL queryClosing( const EventObject& Source, sal_Bool GetsOwnership ) override; + virtual void SAL_CALL notifyClosing( const EventObject& Source ) override; + + // XEventListener + virtual void SAL_CALL disposing( const EventObject& Source) override; + + bool hasOwnership() const { return m_bHasOwnership; } + + protected: + virtual ~CloseListener_Impl() override + { + } + + private: + bool m_bHasOwnership; + }; + + } + + void SAL_CALL CloseListener_Impl::queryClosing( const EventObject&, sal_Bool i_deliverOwnership ) + { + if ( !m_bHasOwnership ) + m_bHasOwnership = i_deliverOwnership; + + throw CloseVetoException(); + } + + void SAL_CALL CloseListener_Impl::notifyClosing( const EventObject& ) {} + + void SAL_CALL CloseListener_Impl::disposing( const EventObject& ) {} + + //= CloseVeto_Data + + struct CloseVeto_Data + { + Reference< XCloseable > xCloseable; + ::rtl::Reference< CloseListener_Impl > pListener; + }; + + //= operations + + namespace + { + + void lcl_init( CloseVeto_Data& i_data, const Reference< XInterface >& i_closeable, + bool const hasOwnership) + { + i_data.xCloseable.set( i_closeable, UNO_QUERY ); + ENSURE_OR_RETURN_VOID( i_data.xCloseable.is(), "CloseVeto: the component is not closeable!" ); + + i_data.pListener = new CloseListener_Impl(hasOwnership); + i_data.xCloseable->addCloseListener( i_data.pListener.get() ); + } + + void lcl_deinit( CloseVeto_Data const & i_data ) + { + if ( !i_data.xCloseable.is() ) + return; + + i_data.xCloseable->removeCloseListener( i_data.pListener.get() ); + if ( i_data.pListener->hasOwnership() ) + { + try + { + i_data.xCloseable->close( true ); + } + catch( const CloseVetoException& ) { } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("unotools"); + } + } + } + } + + //= CloseVeto + CloseVeto::CloseVeto(const Reference< XInterface >& i_closeable, + bool const hasOwnership) + : m_xData(new CloseVeto_Data) + { + lcl_init(*m_xData, i_closeable, hasOwnership); + } + + CloseVeto::~CloseVeto() + { + lcl_deinit(*m_xData); + } + +} // namespace utl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/misc/datetime.cxx b/unotools/source/misc/datetime.cxx new file mode 100644 index 000000000..703ce9127 --- /dev/null +++ b/unotools/source/misc/datetime.cxx @@ -0,0 +1,525 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <unotools/datetime.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/syslocale.hxx> +#include <tools/date.hxx> +#include <tools/time.hxx> +#include <tools/datetime.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/math.hxx> +#include <osl/diagnose.h> +#include <comphelper/string.hxx> +#include <sstream> + +namespace +{ + bool checkAllNumber(const OUString& rString) + { + sal_Int32 nPos = 0; + sal_Int32 nLen = rString.getLength(); + + // skip white space + while( nPos < nLen && ' ' == rString[nPos] ) + nPos++; + + if( nPos < nLen && '-' == rString[nPos] ) + nPos++; + + // get number + while( nPos < nLen && + '0' <= rString[nPos] && + '9' >= rString[nPos] ) + { + nPos++; + } + + return nPos == nLen; + } + + /** convert string to number with optional min and max values */ + bool convertNumber32(sal_Int32& rValue, + const OUString& rString, + sal_Int32 /*nMin*/ = -1, sal_Int32 /*nMax*/ = -1) + { + if (!checkAllNumber(rString)) + { + rValue = 0; + return false; + } + + rValue = rString.toInt32(); + return true; + } + + bool convertNumber64(sal_Int64& rValue, + const OUString& rString, + sal_Int64 /*nMin*/ = -1, sal_Int64 /*nMax*/ = -1) + { + if (!checkAllNumber(rString)) + { + rValue = 0; + return false; + } + + rValue = rString.toInt64(); + return true; + } + + // although the standard calls for fixed-length (zero-padded) tokens + // (in their integer part), we are here liberal and allow shorter tokens + // (when there are separators, else it is ambiguous). + // Note that: + // the token separator is OPTIONAL + // empty string is a valid token! (to recognise hh or hhmm or hh:mm formats) + // returns: success / failure + // in case of failure, no reference argument is changed + // arguments: + // i_str: string to extract token from + // index: index in i_str where to start tokenizing + // after return, start of *next* token (if any) + // if this was the last token, then the value is UNDEFINED + // o_strInt: output; integer part of token + // o_bFraction: output; was there a fractional part? + // o_strFrac: output; fractional part of token + bool impl_getISO8601TimeToken(const OUString &i_str, sal_Int32 &nPos, OUString &resInt, bool &bFraction, OUString &resFrac) + { + bFraction = false; + // all tokens are of length 2 + const sal_Int32 nEndPos = nPos + 2; + const sal_Unicode c0 = '0'; + const sal_Unicode c9 = '9'; + const sal_Unicode sep = ':'; + for (;nPos < nEndPos && nPos < i_str.getLength(); ++nPos) + { + const sal_Unicode c = i_str[nPos]; + if (c == sep) + return true; + if (c < c0 || c > c9) + return false; + resInt += OUStringChar(c); + } + if (nPos == i_str.getLength() || i_str[nPos] == sep) + return true; + if (i_str[nPos] == ',' || i_str[nPos] == '.') + { + bFraction = true; + ++nPos; + for (; nPos < i_str.getLength(); ++nPos) + { + const sal_Unicode c = i_str[nPos]; + if (c == 'Z' || c == '+' || c == '-') + { + --nPos; // we don't want to skip the tz separator + return true; + } + if (c == sep) + // fractional part allowed only in *last* token + return false; + if (c < c0 || c > c9) + return false; + resFrac += OUStringChar(c); + } + OSL_ENSURE(nPos == i_str.getLength(), "impl_getISO8601TimeToken internal error; expected to be at end of string"); + return true; + } + if (i_str[nPos] == 'Z' || i_str[nPos] == '+' || i_str[nPos] == '-') + { + --nPos; // we don't want to skip the tz separator + return true; + } + else + return false; + } + bool getISO8601TimeToken(const OUString &i_str, sal_Int32 &io_index, OUString &o_strInt, bool &o_bFraction, OUString &o_strFrac) + { + OUString resInt; + OUString resFrac; + bool bFraction = false; + sal_Int32 index = io_index; + if(!impl_getISO8601TimeToken(i_str, index, resInt, bFraction, resFrac)) + return false; + else + { + io_index = index+1; + o_strInt = resInt; + o_strFrac = resFrac; + o_bFraction = bFraction; + return true; + } + } + bool getISO8601TimeZoneToken(const OUString &i_str, sal_Int32 &io_index, OUString &o_strInt) + { + const sal_Unicode c0 = '0'; + const sal_Unicode c9 = '9'; + const sal_Unicode sep = ':'; + if (i_str[io_index] == 'Z') // UTC timezone indicator + { + ++io_index; + o_strInt = "Z"; + return true; + } + else if (i_str[io_index] == '+' || i_str[io_index] == '-') // other timezones indicator + { + ++io_index; + o_strInt.clear(); + for (; io_index < i_str.getLength(); ++io_index) + { + const sal_Unicode c = i_str[io_index]; + if ((c < c0 || c > c9) && c != sep) + return false; + o_strInt += OUStringChar(c); + } + return true; + } + else + return false; + } +} + +namespace utl +{ +const LocaleDataWrapper& GetLocaleData() +{ + static SvtSysLocale ourSysLocale; + return ourSysLocale.GetLocaleData(); +} + +DateTime GetDateTime(const css::util::DateTime& _rDT) { return DateTime(_rDT); } + +OUString GetDateTimeString(const css::util::DateTime& _rDT) +{ + // String with date and time information (#i20172#) + DateTime aDT(GetDateTime(_rDT)); + const LocaleDataWrapper& rLoDa = GetLocaleData(); + + return rLoDa.getDate(aDT) + " " + rLoDa.getTime(aDT); +} + +OUString GetDateTimeString(sal_Int32 _nDate, sal_Int32 _nTime) +{ + const LocaleDataWrapper& rLoDa = GetLocaleData(); + + Date aDate(_nDate); + tools::Time aTime(_nTime * tools::Time::nanoPerCenti); + return rLoDa.getDate(aDate) + ", " + rLoDa.getTime(aTime); +} + +OUString GetDateString(const css::util::DateTime& _rDT) +{ + return GetLocaleData().getDate(GetDateTime(_rDT)); +} + +void typeConvert(const Date& _rDate, css::util::Date& _rOut) +{ + _rOut.Day = _rDate.GetDay(); + _rOut.Month = _rDate.GetMonth(); + _rOut.Year = _rDate.GetYear(); +} + +void typeConvert(const css::util::Date& _rDate, Date& _rOut) +{ + _rOut = Date(_rDate.Day, _rDate.Month, _rDate.Year); +} + +void typeConvert(const DateTime& _rDateTime, css::util::DateTime& _rOut) +{ + _rOut.Year = _rDateTime.GetYear(); + _rOut.Month = _rDateTime.GetMonth(); + _rOut.Day = _rDateTime.GetDay(); + _rOut.Hours = _rDateTime.GetHour(); + _rOut.Minutes = _rDateTime.GetMin(); + _rOut.Seconds = _rDateTime.GetSec(); + _rOut.NanoSeconds = _rDateTime.GetNanoSec(); +} + +void typeConvert(const css::util::DateTime& _rDateTime, DateTime& _rOut) +{ + Date aDate(_rDateTime.Day, _rDateTime.Month, _rDateTime.Year); + tools::Time aTime(_rDateTime.Hours, _rDateTime.Minutes, _rDateTime.Seconds, _rDateTime.NanoSeconds); + _rOut = DateTime(aDate, aTime); +} + +OUString toISO8601(const css::util::DateTime& rDateTime) +{ + OUStringBuffer rBuffer(32); + rBuffer.append(static_cast<sal_Int32>(rDateTime.Year)); + rBuffer.append('-'); + if( rDateTime.Month < 10 ) + rBuffer.append('0'); + rBuffer.append(static_cast<sal_Int32>(rDateTime.Month)); + rBuffer.append('-'); + if( rDateTime.Day < 10 ) + rBuffer.append('0'); + rBuffer.append(static_cast<sal_Int32>(rDateTime.Day)); + + if( rDateTime.NanoSeconds != 0 || + rDateTime.Seconds != 0 || + rDateTime.Minutes != 0 || + rDateTime.Hours != 0 ) + { + rBuffer.append('T'); + if( rDateTime.Hours < 10 ) + rBuffer.append('0'); + rBuffer.append(static_cast<sal_Int32>(rDateTime.Hours)); + rBuffer.append(':'); + if( rDateTime.Minutes < 10 ) + rBuffer.append('0'); + rBuffer.append(static_cast<sal_Int32>(rDateTime.Minutes)); + rBuffer.append(':'); + if( rDateTime.Seconds < 10 ) + rBuffer.append('0'); + rBuffer.append(static_cast<sal_Int32>(rDateTime.Seconds)); + if ( rDateTime.NanoSeconds > 0) + { + OSL_ENSURE(rDateTime.NanoSeconds < 1000000000,"NanoSeconds cannot be more than 999 999 999"); + rBuffer.append(','); + std::ostringstream ostr; + ostr.fill('0'); + ostr.width(9); + ostr << rDateTime.NanoSeconds; + rBuffer.append(OUString::createFromAscii(ostr.str().c_str())); + } + } + return rBuffer.makeStringAndClear(); +} + +/** convert ISO8601 DateTime String to util::DateTime */ +bool ISO8601parseDateTime(const OUString &rString, css::util::DateTime& rDateTime) +{ + bool bSuccess = true; + + OUString aDateStr, aTimeStr; + css::util::Date aDate; + css::util::Time aTime; + sal_Int32 nPos = rString.indexOf( 'T' ); + if ( nPos >= 0 ) + { + aDateStr = rString.copy( 0, nPos ); + aTimeStr = rString.copy( nPos + 1 ); + } + else + aDateStr = rString; // no separator: only date part + + bSuccess = ISO8601parseDate(aDateStr, aDate); + + if ( bSuccess && !aTimeStr.isEmpty() ) // time is optional + { + bSuccess = ISO8601parseTime(aTimeStr, aTime); + } + + if (bSuccess) + { + rDateTime = css::util::DateTime(aTime.NanoSeconds, aTime.Seconds, aTime.Minutes, aTime.Hours, + aDate.Day, aDate.Month, aDate.Year, false); + } + + return bSuccess; +} + +/** convert ISO8601 Date String to util::Date */ +// TODO: supports only calendar dates YYYY-MM-DD +// MISSING: calendar dates YYYYMMDD YYYY-MM +// year, week date, ordinal date +bool ISO8601parseDate(const OUString &aDateStr, css::util::Date& rDate) +{ + const sal_Int32 nDateTokens {comphelper::string::getTokenCount(aDateStr, '-')}; + + if (nDateTokens<1 || nDateTokens>3) + return false; + + sal_Int32 nYear = 1899; + sal_Int32 nMonth = 12; + sal_Int32 nDay = 30; + + sal_Int32 nIdx {0}; + if ( !convertNumber32( nYear, aDateStr.getToken( 0, '-', nIdx ), 0, 9999 ) ) + return false; + if ( nDateTokens >= 2 ) + if ( !convertNumber32( nMonth, aDateStr.getToken( 0, '-', nIdx ), 0, 12 ) ) + return false; + if ( nDateTokens >= 3 ) + if ( !convertNumber32( nDay, aDateStr.getToken( 0, '-', nIdx ), 0, 31 ) ) + return false; + + rDate.Year = static_cast<sal_uInt16>(nYear); + rDate.Month = static_cast<sal_uInt16>(nMonth); + rDate.Day = static_cast<sal_uInt16>(nDay); + + return true; +} + +/** convert ISO8601 Time String to util::Time */ +bool ISO8601parseTime(const OUString &aTimeStr, css::util::Time& rTime) +{ + sal_Int32 nHour = 0; + sal_Int32 nMin = 0; + sal_Int32 nSec = 0; + sal_Int32 nNanoSec = 0; + + sal_Int32 n = 0; + OUString tokInt; + OUString tokFrac; + OUString tokTz; + bool bFrac = false; + // hours + bool bSuccess = getISO8601TimeToken(aTimeStr, n, tokInt, bFrac, tokFrac); + if (!bSuccess) + return false; + + if ( bFrac && n < aTimeStr.getLength()) + { + // is it junk or the timezone? + bSuccess = getISO8601TimeZoneToken(aTimeStr, n, tokTz); + if (!bSuccess) + return false; + } + bSuccess = convertNumber32( nHour, tokInt, 0, 23 ); + if (!bSuccess) + return false; + + if (bFrac) + { + sal_Int64 fracNumerator; + bSuccess = convertNumber64(fracNumerator, tokFrac); + if ( bSuccess ) + { + double frac = static_cast<double>(fracNumerator) / pow(static_cast<double>(10), static_cast<double>(tokFrac.getLength())); + // minutes + OSL_ENSURE(frac < 1 && frac >= 0, "ISO8601parse internal error frac hours (of hours) not between 0 and 1"); + frac *= 60; + nMin = floor(frac); + frac -= nMin; + // seconds + OSL_ENSURE(frac < 1 && frac >= 0, "ISO8601parse internal error frac minutes (of hours) not between 0 and 1"); + frac *= 60; + nSec = floor(frac); + frac -= nSec; + // nanoseconds + OSL_ENSURE(frac < 1 && frac >= 0, "ISO8601parse internal error frac seconds (of hours) not between 0 and 1"); + frac *= 1000000000; + nNanoSec = ::rtl::math::round(frac); + } + goto end; + } + if(n >= aTimeStr.getLength()) + goto end; + + // minutes + bSuccess = getISO8601TimeToken(aTimeStr, n, tokInt, bFrac, tokFrac); + if (!bSuccess) + return false; + if ( bFrac && n < aTimeStr.getLength()) + { + // is it junk or the timezone? + bSuccess = getISO8601TimeZoneToken(aTimeStr, n, tokTz); + if (!bSuccess) + return false; + } + bSuccess = convertNumber32( nMin, tokInt, 0, 59 ); + if (!bSuccess) + return false; + if (bFrac) + { + sal_Int64 fracNumerator; + bSuccess = convertNumber64(fracNumerator, tokFrac); + if ( bSuccess ) + { + double frac = static_cast<double>(fracNumerator) / pow(static_cast<double>(10), static_cast<double>(tokFrac.getLength())); + // seconds + OSL_ENSURE(frac < 1 && frac >= 0, "ISO8601parse internal error frac minutes (of minutes) not between 0 and 1"); + frac *= 60; + nSec = floor(frac); + frac -= nSec; + // nanoseconds + OSL_ENSURE(frac < 1 && frac >= 0, "ISO8601parse internal error frac seconds (of minutes) not between 0 and 1"); + frac *= 1000000000; + nNanoSec = ::rtl::math::round(frac); + } + goto end; + } + if(n >= aTimeStr.getLength()) + goto end; + + // seconds + bSuccess = getISO8601TimeToken(aTimeStr, n, tokInt, bFrac, tokFrac); + if (!bSuccess) + return false; + if (n < aTimeStr.getLength()) + { + // is it junk or the timezone? + bSuccess = getISO8601TimeZoneToken(aTimeStr, n, tokTz); + if (!bSuccess) + return false; + } + // max 60 for leap seconds + bSuccess = convertNumber32( nSec, tokInt, 0, 60 ); + if (!bSuccess) + return false; + if (bFrac) + { + sal_Int64 fracNumerator; + bSuccess = convertNumber64(fracNumerator, tokFrac); + if ( bSuccess ) + { + double frac = static_cast<double>(fracNumerator) / pow(static_cast<double>(10), static_cast<double>(tokFrac.getLength())); + // nanoseconds + OSL_ENSURE(frac < 1 && frac >= 0, "ISO8601parse internal error frac seconds (of seconds) not between 0 and 1"); + frac *= 1000000000; + nNanoSec = ::rtl::math::round(frac); + } + goto end; + } + + end: + if (bSuccess) + { + // normalise time + const int secondsOverflow = (nSec == 60) ? 61 : 60; + if (nNanoSec == 1000000000) + { + nNanoSec = 0; + ++nSec; + } + if(nSec == secondsOverflow) + { + nSec = 0; + ++nMin; + } + if(nMin == 60) + { + nMin = 0; + ++nHour; + } + if(!tokTz.isEmpty()) + rTime.IsUTC = (tokTz == "Z"); + + rTime.Hours = static_cast<sal_uInt16>(nHour); + rTime.Minutes = static_cast<sal_uInt16>(nMin); + rTime.Seconds = static_cast<sal_uInt16>(nSec); + rTime.NanoSeconds = nNanoSec; + } + + return bSuccess; +} + +} // namespace utl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/misc/defaultencoding.cxx b/unotools/source/misc/defaultencoding.cxx new file mode 100644 index 000000000..552f3b8c4 --- /dev/null +++ b/unotools/source/misc/defaultencoding.cxx @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <sal/config.h> + +#include <unotools/configmgr.hxx> +#include <unotools/defaultencoding.hxx> +#include <officecfg/Office/Linguistic.hxx> +#include <officecfg/Setup.hxx> +#include <officecfg/System.hxx> + +OUString utl_getLocaleForGlobalDefaultEncoding() +{ + if (utl::ConfigManager::IsFuzzing()) + return "en-US"; + // First try document default language + OUString result(officecfg::Office::Linguistic::General::DefaultLocale::get()); + // Fallback to LO locale + if (result.isEmpty()) + result = officecfg::Setup::L10N::ooSetupSystemLocale::get(); + // Fallback to system locale + if (result.isEmpty()) + result = officecfg::System::L10N::Locale::get(); + return result; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/misc/desktopterminationobserver.cxx b/unotools/source/misc/desktopterminationobserver.cxx new file mode 100644 index 000000000..f5ea04bd4 --- /dev/null +++ b/unotools/source/misc/desktopterminationobserver.cxx @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <unotools/desktopterminationobserver.hxx> + +#include <com/sun/star/frame/TerminationVetoException.hpp> +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <cppuhelper/implbase.hxx> +#include <comphelper/processfactory.hxx> +#include <osl/diagnose.h> +#include <tools/diagnose_ex.h> + +#include <vector> + +namespace utl +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::frame; + + namespace + { + + typedef ::std::vector< ITerminationListener* > Listeners; + + struct ListenerAdminData + { + Listeners aListeners; + bool bAlreadyTerminated; + bool bCreatedAdapter; + + ListenerAdminData() : bAlreadyTerminated( false ), bCreatedAdapter( false ) { } + }; + + ListenerAdminData& getListenerAdminData() + { + static ListenerAdminData s_aData; + return s_aData; + } + + //= OObserverImpl + + class OObserverImpl : public ::cppu::WeakImplHelper< XTerminateListener > + { + public: + static void ensureObservation(); + + private: + OObserverImpl(); + virtual ~OObserverImpl() override; + + // XTerminateListener + virtual void SAL_CALL queryTermination( const EventObject& Event ) override; + virtual void SAL_CALL notifyTermination( const EventObject& Event ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + }; + + OObserverImpl::OObserverImpl() + { + } + + OObserverImpl::~OObserverImpl() + { + } + + void OObserverImpl::ensureObservation() + { + { + if ( getListenerAdminData().bCreatedAdapter ) + return; + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if ( getListenerAdminData().bCreatedAdapter ) + return; + + getListenerAdminData().bCreatedAdapter = true; + } + + try + { + Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() ); + xDesktop->addTerminateListener( new OObserverImpl ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "unotools", "OObserverImpl::ensureObservation" ); + } + } + + void SAL_CALL OObserverImpl::queryTermination( const EventObject& /*Event*/ ) + { + Listeners aToNotify; + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + aToNotify = getListenerAdminData().aListeners; + } + + for (auto const& listener : aToNotify) + { + if ( !listener->queryTermination() ) + throw TerminationVetoException(); + } + } + + void SAL_CALL OObserverImpl::notifyTermination( const EventObject& /*Event*/ ) + { + // get the listeners + Listeners aToNotify; + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + OSL_ENSURE( !getListenerAdminData().bAlreadyTerminated, "OObserverImpl::notifyTermination: terminated twice?" ); + aToNotify = getListenerAdminData().aListeners; + getListenerAdminData().bAlreadyTerminated = true; + } + + // notify the listeners + for (auto const& listener : aToNotify) + { + listener->notifyTermination(); + } + + // clear the listener container + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + getListenerAdminData().aListeners.clear(); + } + } + + void SAL_CALL OObserverImpl::disposing( const EventObject& /*Event*/ ) + { +#if OSL_DEBUG_LEVEL > 0 + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + OSL_ENSURE( getListenerAdminData().bAlreadyTerminated, "OObserverImpl::disposing: disposing without terminated?" ); +#endif + // not interested in + } + } + + //= DesktopTerminationObserver + + void DesktopTerminationObserver::registerTerminationListener( ITerminationListener* _pListener ) + { + if ( !_pListener ) + return; + + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if ( getListenerAdminData().bAlreadyTerminated ) + { + _pListener->notifyTermination(); + return; + } + + getListenerAdminData().aListeners.push_back( _pListener ); + } + + OObserverImpl::ensureObservation(); + } + + void DesktopTerminationObserver::revokeTerminationListener( ITerminationListener const * _pListener ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + Listeners& rListeners = getListenerAdminData().aListeners; + rListeners.erase(std::remove(rListeners.begin(), rListeners.end(), _pListener), rListeners.end()); + } + +} // namespace utl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/misc/eventlisteneradapter.cxx b/unotools/source/misc/eventlisteneradapter.cxx new file mode 100644 index 000000000..d9736905d --- /dev/null +++ b/unotools/source/misc/eventlisteneradapter.cxx @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <vector> + +#include <com/sun/star/lang/XComponent.hpp> +#include <unotools/eventlisteneradapter.hxx> +#include <osl/diagnose.h> +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> + +namespace utl +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + + //= OEventListenerImpl + + class OEventListenerImpl : public ::cppu::WeakImplHelper< XEventListener > + { + protected: + OEventListenerAdapter* m_pAdapter; + Reference< XEventListener > m_xKeepMeAlive; + // imagine an implementation of XComponent which holds it's listeners with a weak reference ... + // would be very bad if we don't hold ourself + Reference< XComponent > m_xComponent; + + public: + OEventListenerImpl( OEventListenerAdapter* _pAdapter, const Reference< XComponent >& _rxComp ); + + void dispose(); + const Reference< XComponent >& getComponent() const { return m_xComponent; } + + protected: + virtual void SAL_CALL disposing( const EventObject& _rSource ) override; + }; + + OEventListenerImpl::OEventListenerImpl( OEventListenerAdapter* _pAdapter, const Reference< XComponent >& _rxComp ) + :m_pAdapter(_pAdapter) + { + OSL_ENSURE(m_pAdapter, "OEventListenerImpl::OEventListenerImpl: invalid adapter!"); + // no checks of _rxComp !! + // (OEventListenerAdapter is responsible for this) + + // just in case addEventListener throws an exception ... don't initialize m_xKeepMeAlive before this + // is done + Reference< XEventListener > xMeMyselfAndI = this; + _rxComp->addEventListener(xMeMyselfAndI); + + m_xComponent = _rxComp; + m_xKeepMeAlive = xMeMyselfAndI; + } + + void OEventListenerImpl::dispose() + { + if (m_xComponent.is()) + { + if (m_xKeepMeAlive.is()) + m_xComponent->removeEventListener(m_xKeepMeAlive); + m_xComponent.clear(); + m_xKeepMeAlive.clear(); + } + } + + void SAL_CALL OEventListenerImpl::disposing( const EventObject& _rSource ) + { + Reference< XEventListener > xDeleteUponLeaving = m_xKeepMeAlive; + m_xKeepMeAlive.clear(); + + m_pAdapter->_disposing(_rSource); + } + + //= OEventListenerAdapterImpl + + struct OEventListenerAdapterImpl + { + public: + std::vector< rtl::Reference<OEventListenerImpl> > aListeners; + }; + + //= OEventListenerAdapter + + OEventListenerAdapter::OEventListenerAdapter() + :m_pImpl(new OEventListenerAdapterImpl) + { + } + + OEventListenerAdapter::~OEventListenerAdapter() + { + stopAllComponentListening( ); + } + + void OEventListenerAdapter::stopComponentListening( const css::uno::Reference< css::lang::XComponent >& _rxComp ) + { + if ( m_pImpl->aListeners.empty() ) + return; + + auto it = m_pImpl->aListeners.begin(); + do + { + rtl::Reference<OEventListenerImpl>& pListenerImpl = *it; + if ((pListenerImpl->getComponent().get() == _rxComp.get()) || (pListenerImpl->getComponent() == _rxComp)) + { + pListenerImpl->dispose(); + it = m_pImpl->aListeners.erase( it ); + } + else + ++it; + } + while ( it != m_pImpl->aListeners.end() ); + } + + void OEventListenerAdapter::stopAllComponentListening( ) + { + for ( const auto & i : m_pImpl->aListeners ) + { + i->dispose(); + } + m_pImpl->aListeners.clear(); + } + + void OEventListenerAdapter::startComponentListening( const Reference< XComponent >& _rxComp ) + { + if (!_rxComp.is()) + { + OSL_FAIL("OEventListenerAdapter::startComponentListening: invalid component!"); + return; + } + + OEventListenerImpl* pListenerImpl = new OEventListenerImpl(this, _rxComp); + m_pImpl->aListeners.emplace_back(pListenerImpl); + } + +} // namespace utl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/misc/fontcvt.cxx b/unotools/source/misc/fontcvt.cxx new file mode 100644 index 000000000..6a04e7d61 --- /dev/null +++ b/unotools/source/misc/fontcvt.cxx @@ -0,0 +1,1443 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <unotools/fontcvt.hxx> +#include <unotools/fontdefs.hxx> +#include <sal/macros.h> + +#include <map> +#include <vector> + +//These conversion tables were designed for StarSymbol. OpenSymbol +//originally didn't have the same code points as StarSymbol, and +//then gained some extra code points, but there are still potentially +//various holes in OpenSymbol which were filled by StarSymbol, i.e. +//destination mapping points which are empty in OpenSymbol + +// note: the character mappings that are only approximations +// are marked (with an empty comment) + +static const sal_Unicode aStarBatsTab[224] = +{ + // F020 + 0x0020, 0x263a, 0x25cf, 0x274d, + 0x25a0, 0x25a1, 0xE000, 0x2751, + 0x2752, 0xE001, 0xE002, 0xE003, + 0x2756, 0xE004, 0xE005, 0x27a2, + // F030 + 0xE006, 0x2794, 0x2713, 0x2612, + 0x2611, 0x27b2, 0x261b, 0x270d, + 0x270e, 0xE007, 0x2714, 0xE008, + 0xE009, 0xE00A, 0x274f, 0x2750, + // F040 + 0xE00B, 0xE00C, 0xE00D, 0xE00E, + 0x2722, 0x2723, 0x2724, 0x2725, + 0x2733, 0x2734, 0x2735, 0x2736, + 0x2737, 0x2738, 0x2739, 0x2717, + // F050 + 0x2718, 0x2719, 0x271a, 0x271b, + 0x271c, 0x272b, 0x272c, 0x272d, + 0x272e, 0x272f, 0x2730, 0, + 0xE00F, 0x278a, 0x278b, 0x278c, + // F060 + 0x278d, 0x278e, 0x278f, 0x2790, + 0x2791, 0x2792, 0x2793, 0xE010, + 0x2780, 0x2781, 0x2782, 0x2783, + 0x2784, 0x2785, 0x2786, 0x2787, + // F070 + 0x2788, 0x2789, 0xE011, 0xE012, + 0x260e, 0xE013, 0xE014, 0xE015, + 0xE016, 0xE017, 0xE018, 0xE019, + 0xE01A, 0x261e, 0xE01B, 0, + // F080 + 0x20ac, 0, 0x201a, 0x0192, + 0x201e, 0x2026, 0x2020, 0x2021, + 0xE01c, 0x2030, 0x0160, 0x2039, + 0x0152, 0, 0x017d, 0, + // F090 + 0, 0x2018, 0x2019, 0x201c, + 0x201d, 0x2022, 0x2013, 0x2014, + 0xE01d, 0x2122, 0x0161, 0x203a, + 0x0153, 0, 0x017e, 0x0178, + // F0A0 + 0, 0x21e7, 0x21e8, 0x21e9, + 0x21e6, 0xE01e, 0xE01f, 0x00a7, + 0xE020, 0xE021, 0xE022, 0x00ab, + 0xE023, 0x2639, 0xE024, 0xE025, + // F0B0 + 0xE026, 0xE027, 0xE028, 0x21e5, + 0x21e4, 0x2192, 0x2193, 0x2190, + 0x2191, 0xE029, 0xE02a, 0x00bb, + 0xE02b, 0xE02c, 0xE02d, 0xE02e, + // F0C0 + 0xE02f, 0xE030, 0xE031, 0xE032, + 0x25be, 0x25b4, 0x25bf, 0x25b5, + 0xE033, 0xE034, 0xE035, 0x2702, + 0x2708, 0x2721, 0x273f, 0x2744, + // F0D0 + 0x25d7, 0x2759, 0xE036, 0xE037, + 0x2762, 0x2663, 0x2665, 0x2660, + 0x2194, 0x2195, 0x2798, 0x279a, + 0x27b8, 0, 0x00b6, 0, + // F0E0 + 0x00a2, 0x00a4, 0x00a5, 0xE038, + 0x20a1, 0x20a2, 0x20a3, 0x20a4, + 0x20a9, 0x20ab, 0x20a8, 0xE039, + 0, 0, 0, 0, + // F0F0 + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0xE03a +}; + +static const sal_Unicode aStarMathTab[224] = +{ + // F020 + 0x0020, 0x0021, 0x0022, 0x0023, + 0xE080, 0x0025, 0x0026, 0x221e, + 0x0028, 0x0029, 0x002a, 0x002b, + 0x002c, 0x002d, 0x002e, 0x002f, + // F030 + 0x2224, 0x21d2, 0x21d0, 0x21d4, + 0xE081, 0xE082, 0x00b0, 0, + 0, 0, 0x003a, 0x003b, + 0x003c, 0x003d, 0x003e, 0x00bf, + // F040 + 0x2260, 0xE083, 0x2212, 0x2217, + 0x00d7, 0x22c5, 0x00f7, 0x00b1, + 0x2213, 0x2295, 0x2296, 0x2297, + 0x2298, 0x2299, 0x222a, 0x2229, + // F050 + 0xE084, 0xE085, 0x2264, 0x2265, + 0xE086, 0xE087, 0x226a, 0x226b, + 0x007e, 0x2243, 0x2248, 0x225d, + 0x2261, 0x221d, 0x2202, 0x2282, + // F060 + 0x2283, 0x2286, 0x2287, 0x2284, + 0x2285, 0x2288, 0x2289, 0x2208, + 0x2209, 0xE089, 0x2203, 0x220d, + 0x2135, 0x2111, 0x211c, 0x2118, + // F070 + 0xE08a, 0x2221, 0x2222, 0x2223, + 0x2225, 0x22a5, 0xE08b, 0x22ef, + 0x22ee, 0x22f0, 0x22f1, 0x22b6, + 0x22b7, 0xE08c, 0x2216, 0x00ac, + // F080 + 0x222b, 0x222c, 0x222d, 0x222e, + 0x222f, 0x2230, 0x221a, 0xE08d, + 0xE08e, 0xE08f, 0x2210, 0x220f, + 0x2211, 0x2207, 0x2200, 0xE090, + // F090 + 0xE091, 0xE092, 0xE093, 0xE094, + 0xE095, 0xE096, 0xE097, 0xE098, + 0x02d9, 0x00a8, 0xE09b, 0x02da, + 0x2227, 0x2228, 0x220b, 0x2205, + // F0A0 + 0x007b, 0x007d, 0xe09e, 0xe09f, + 0x2329, 0x232a, 0x005b, 0x005d, + 0xE0a0, 0x22be, 0xE0a1, 0x2259, + 0x2254, 0x2255, 0x21b3, 0x2197, + // F0B0 + 0x2198, 0x2245, 0x301a, 0x301b, + 0x2373, 0xE0a5, 0xE0a6, 0x22a4, + 0x2112, 0x2130, 0x2131, 0, + 0xE0a7, 0xE0a8, 0xE0a9, 0xE0aa, + // F0C0 + 0x2308, 0x230a, 0x2309, 0x230b, + 0, 0xe0ab, 0xe0ac, 0xe0ad, + 0xe0ae, 0xe0af, 0xe0b0, 0xe0b1, + 0xe0b2, 0xe0b3, 0xe0b4, 0xe0b5, + // F0D0 + 0xe0b6, 0xe0b7, 0xe0b8, 0xe0b9, + 0xe0ba, 0xe0bb, 0xe0bc, 0xe0bd, + 0xe0be, 0xe0bf, 0xe0c0, 0xe0c1, + 0xe0c2, 0xe0c3, 0xe0c4, 0xe0c5, + // F0E0 + 0xe0c6, 0xe0c7, 0xe0c8, 0xe0c9, + 0xe0ca, 0xe0cb, 0xe0cc, 0xe0cd, + 0xe0ce, 0xe0cf, 0xe0d0, 0xe0d1, + 0x03f1, 0xe0d3, 0xe0d4, 0xe0d5, + // F0F0 + 0x2113, 0xe0d6, 0x2107, 0x2127, + 0x210a, 0xe0d9, 0x210f, 0x019b, + 0xe0db, 0xe0dc, 0xe0dd, 0x2115, + 0x2124, 0x211a, 0x211d, 0x2102 +}; + +static const sal_Unicode aWingDingsTab[224] = +{ + // F020 + 0x0020, 0xe400, 0xe401, 0xe402, + 0xe403, 0xe404, 0xe405, 0xe406, + 0xe407, 0xe408, 0xe409, 0xe40a, + 0xe40b, 0xe40c, 0xe40d, 0xe40e, + // F030 + 0xe40f, 0xe410, 0xe411, 0xe412, + 0xe413, 0xe414, 0xe415, 0xe416, + 0xe417, 0xe418, 0xe419, 0xe41a, + 0xe41b, 0xe41c, 0x2707, 0xe41d, + // F040 + 0xe41e, 0xe41f, 0xe420, 0xe421, + 0x261c, 0xe423, 0x261d, 0x261f, + 0x261f, 0xe424, 0xe425, 0xe426, + 0xe427, 0xe428, 0xe429, 0xe42a, + // F050 + 0xe42b, 0xe42c, 0x263c, 0xe42d, + 0xe42e, 0xe42f, 0xe430, 0xe431, + 0xe432, 0xe433, 0x262a, 0x262f, + 0x0950, 0xe434, 0x2648, 0x2649, + // F060 + 0x264a, 0x264b, 0x264c, 0x264d, + 0x264e, 0x264f, 0x2650, 0x2651, + 0x2652, 0x2653, 0xe435, 0xe436, + 0xe437, 0xe438, 0xe439, 0xe43a, + // F070 + 0xe43b, 0xe43c, 0xe43d, 0xe43e, + 0xe43f, 0xe440, 0xe441, 0xe442, + 0xe443, 0x2353, 0x2318, 0xe444, + 0xe445, 0xe446, 0xe447, 0, + // F080 + 0xe448, 0xe449, 0xe44a, 0xe44b, + 0xe44c, 0xe44d, 0xe44e, 0xe44f, + 0xe450, 0xe451, 0xe452, 0xe453, + 0xe454, 0xe455, 0xe456, 0xe457, + // F090 + 0xe458, 0xe459, 0xe45a, 0xe45b, + 0xe45c, 0xe45d, 0xe45e, 0xe45f, + 0xe460, 0xe461, 0xe462, 0xe463, + 0xe464, 0xe465, 0xe466, 0xe467, + // F0a0 + 0xe468, 0xe469, 0xe46a, 0xe46b, + 0xe46c, 0xe46d, 0xe46e, 0xe46f, + 0xe470, 0xe471, 0xe472, 0xe473, + 0xe474, 0xe475, 0xe476, 0xe477, + // F0b0 + 0xe478, 0xe479, 0xe47a, 0xe47b, + 0xe47c, 0xe47d, 0xe47e, 0xe47f, + 0xe480, 0xe481, 0xe482, 0xe483, + 0xe484, 0xe485, 0xe486, 0xe487, + // F0c0 + 0xe488, 0xe489, 0xe48a, 0xe48b, + 0xe48c, 0xe48d, 0xe48e, 0xe48f, + 0xe490, 0xe491, 0xe492, 0xe493, + 0xe494, 0xe495, 0xe496, 0xe497, + // F0d0 + 0xe498, 0xe499, 0xe49a, 0xe49b, + 0xe49c, 0x232b, 0x2326, 0xe49d, + 0xe49e, 0xe49f, 0xe4a0, 0xe4a1, + 0xe4a2, 0xe4a3, 0xe4a4, 0xe4a5, + // F0e0 + 0xe4a6, 0xe4a7, 0xe4a8, 0xe4a9, + 0xe4aa, 0xe4ab, 0xe4ac, 0xe4ad, + 0xe4ae, 0xe4af, 0xe4b0, 0xe4b1, + 0xe4b2, 0xe4b3, 0xe4b4, 0xe4b5, + // F0f0 + 0xe4b6, 0xe4b7, 0xe4b8, 0xe4b9, + 0xe4ba, 0xe4bb, 0xe4bc, 0xe4bd, + 0xe4be, 0xe4bf, 0xe4c0, 0xe4c1, + 0xe4c2, 0xe4c3, 0xe4c4, 0xe4c5 +}; + +static const sal_Unicode aWingDings2Tab[224] = +{ + // F020 + 0x0020, 0xe500, 0xe501, 0xe502, + 0xe503, 0xe504, 0xe505, 0xe506, + 0xe507, 0xe508, 0xe509, 0xe50a, + 0xe50b, 0xe50c, 0xe50d, 0xe50e, + // F030 + 0xe50f, 0xe510, 0xe511, 0xe512, + 0xe513, 0xe514, 0xe515, 0xe516, + 0xe517, 0xe518, 0xe519, 0xe51a, + 0xe51b, 0xe51c, 0xe51d, 0xe51e, + // F040 + 0xe51f, 0xe520, 0xe521, 0xe522, + 0xe523, 0xe524, 0xe525, 0xe526, + 0xe527, 0xe528, 0xe529, 0xe52a, + 0xe52b, 0xe52c, 0xe52d, 0xe52e, + // F050 + 0xe52f, 0xe530, 0xe531, 0xe532, + 0xe533, 0xe534, 0xe535, 0xe536, + 0xe537, 0x203D, 0x203D, 0x203D, + 0xe53b, 0xe53c, 0xe53d, 0xe53e, + // F060 + 0xe53f, 0xe540, 0xe541, 0xe542, + 0xe543, 0xe544, 0xe545, 0xe546, + 0xe547, 0x24EA, 0x2460, 0x2461, + 0x2462, 0x2463, 0x2464, 0x2465, + // F070 + 0x2466, 0x2467, 0x2468, 0x2469, + 0xE453, 0x278A, 0x278B, 0x278C, + 0x278D, 0x278E, 0x278F, 0x2790, + 0x2791, 0x2792, 0x2793, 0, + // F080 + 0x2609, 0x25cb, 0x263d, 0x263e, + 0xe55d, 0xe55e, 0xe55f, 0xe560, + 0xe561, 0xe562, 0xe563, 0xe564, + 0xe565, 0xe566, 0xe567, 0xe568, + // F090 + 0xe569, 0xe56a, 0xe56b, 0xe56c, + 0xe56d, 0xe56e, 0xe56f, 0xe570, + 0xe571, 0xe572, 0xe573, 0xe574, + 0xe575, 0, 0, 0xe578, + // F0a0 + 0xe579, 0xe57a, 0xe57b, 0xe57c, + 0, 0, 0, 0, + 0, 0, 0, 0xe584, + 0xe585, 0, 0xe586, 0, + // F0b0 + 0, 0, 0, 0, + 0xe58d, 0xe58e, 0xe58f, 0xe590, + 0, 0, 0xe593, 0xe594, + 0, 0, 0, 0xe587, + // F0c0 + 0xe599, 0xe59a, 0xe59b, 0xe59c, + 0xe59d, 0xe59e, 0xe59f, 0xe5a0, + 0xe5a1, 0xe5a2, 0xe5a3, 0xe5a4, + 0xe5a5, 0xe5a6, 0xe5a7, 0xe5a8, + // F0d0 + 0xe5a9, 0xe5aa, 0xe5ab, 0xe5ac, + 0xe5ad, 0xe5ae, 0xe5af, 0xe5b0, + 0xe5b1, 0xe5b2, 0xe5b3, 0xe5b4, + 0xe5b5, 0xe5b6, 0xe5b7, 0xe5b8, + // F0e0 + 0xe5b9, 0xe5ba, 0xe5bb, 0xe5bc, + 0xe5bd, 0xe5be, 0xe5bf, 0xe5c0, + 0xe5c1, 0xe5c2, 0xe5c3, 0xe5c4, + 0xe5c5, 0xe5c6, 0xe5c7, 0xe5c8, + // F0f0 + 0xe5c9, 0, 0xe5cb, 0xe477, + 0xe5cd, 0xe5ce, 0xe5cf, 0xe5d0, + 0x203b, 0x2042, 0, 0, + 0, 0, 0, 0 +}; + +static const sal_Unicode aWingDings3Tab[224] = +{ + // F020 + 0x0020, 0xe600, 0xe601, 0xe602, + 0xe603, 0x2196, 0xe604, 0x2199, + 0xe605, 0xe606, 0xe607, 0xe608, + 0xe609, 0xe60a, 0xe60b, 0x21de, + // F030 + 0x21df, 0xe60c, 0xe60d, 0xe60e, + 0x21e2, 0x21e1, 0x21e3, 0x21af, + 0x21b5, 0xe60f, 0xe610, 0xe611, + 0xe612, 0xe613, 0xe614, 0xe615, + // F040 + 0xe616, 0xe617, 0xe618, 0xe619, + 0x21c4, 0x21c5, 0xe61a, 0xe61b, + 0x21c7, 0x21c9, 0x21c8, 0x21ca, + 0x21b6, 0x21b7, 0xe61c, 0xe61d, + // F050 + 0x21bb, 0x21ba, 0xe61e, 0x2324, + 0x2303, 0x2325, 0x2334, 0xe61f, + 0x21ea, 0xe620, 0xe621, 0xe622, + 0xe623, 0xe624, 0xe625, 0xe626, + // F060 + 0xe627, 0xe628, 0xe629, 0xe62a, + 0xe62b, 0xe62c, 0xe62d, 0xe62e, + 0xe62f, 0xe630, 0xe631, 0xe632, + 0xe633, 0xe634, 0xe635, 0xe636, + // F070 + 0xe637, 0xe638, 0x25b3, 0x25bd, + 0x25c0, 0x25b6, 0x25c1, 0x25b7, + 0x25e3, 0xe639, 0x25e4, 0x25e5, + 0x25c2, 0x25b8, 0xe63a, 0, + // F080 + 0xe63b, 0xe63c, 0xe63d, 0xe63e, + 0xe63f, 0xe640, 0xe641, 0xe642, + 0xe643, 0xe644, 0xe645, 0xe646, + 0xe647, 0xe648, 0xe649, 0xe64a, + // F090 + 0xe64b, 0xe64c, 0xe64d, 0xe64e, + 0xe64f, 0xe650, 0xe651, 0xe652, + 0xe653, 0xe654, 0xe655, 0xe656, + 0xe657, 0xe658, 0xe659, 0xe65a, + // F0a0 + 0xe65b, 0xe65c, 0xe65d, 0xe65e, + 0xe65f, 0xe660, 0xe661, 0xe662, + 0xe663, 0xe664, 0xe665, 0xe666, + 0xe667, 0xe668, 0xe669, 0xe66a, + // F0b0 + 0xe66b, 0xe66c, 0xe66d, 0xe66e, + 0xe66f, 0xe670, 0xe671, 0xe672, + 0xe673, 0xe674, 0xe675, 0xe676, + 0xe677, 0xe678, 0xe679, 0xe67a, + // F0c0 + 0xe67b, 0xe67c, 0xe67d, 0xe67e, + 0xe67f, 0xe680, 0xe681, 0xe682, + 0xe683, 0xe684, 0xe685, 0xe686, + 0xe687, 0xe688, 0xe689, 0xe68a, + // F0d0 + 0xe68b, 0xe68c, 0xe68d, 0xe68e, + 0xe68f, 0xe690, 0xe691, 0xe692, + 0xe693, 0xe694, 0xe695, 0xe696, + 0xe697, 0xe698, 0xe699, 0xe69a, + // F0e0 + 0xe69b, 0xe69c, 0xe69d, 0xe69e, + 0xe69f, 0xe6a0, 0xe6a1, 0xe6a2, + 0xe6a3, 0xe6a4, 0xe6a5, 0xe6a6, + 0xe6a7, 0xe6a8, 0xe6a9, 0xe6aa, + // F0f0 + 0xe6ab, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 +}; + +static const sal_Unicode aWebDingsTab[224] = +{ + // F020 + 0x0020, 0xe300, 0xe301, 0xe302, + 0xe303, 0xe304, 0xe305, 0xe306, + 0xe307, 0xe308, 0xe309, 0xe30a, + 0xe30b, 0xe30c, 0xe30d, 0xe30e, + // F030 + 0xe30f, 0xe310, 0xe311, 0xe312, + 0xe313, 0xe314, 0xe315, 0xe316, + 0xe317, 0xe318, 0xe319, 0xe31a, + 0xe31b, 0xe31c, 0xe31d, 0xe31e, + // F040 + 0xe31f, 0xe320, 0xe321, 0xe322, + 0xe323, 0xe324, 0xe325, 0xe326, + 0xe327, 0xe328, 0xe329, 0xe32a, + 0xe32b, 0xe32c, 0xe32d, 0xe32e, + // F050 + 0xe32f, 0xe330, 0xe331, 0xe332, + 0xe333, 0xe334, 0xe335, 0xe336, + 0xe337, 0xe338, 0xe339, 0xe33a, + 0xe33b, 0xe33c, 0xe33d, 0xe33e, + // F060 + 0xe33f, 0xe340, 0xe341, 0xe342, + 0xe343, 0xe344, 0xe345, 0xe346, + 0xe347, 0xe348, 0xe349, 0xe34a, + 0xe34b, 0xe34c, 0xe34d, 0xe34e, + // F070 + 0xe34f, 0xe350, 0xe351, 0xe352, + 0xe353, 0xe354, 0xe355, 0xe356, + 0xe357, 0xe358, 0xe359, 0xe35a, + 0xe35b, 0xe35c, 0xe35d, 0, + // F080 + 0xe35e, 0xe35f, 0xe360, 0xe361, + 0xe362, 0xe363, 0xe364, 0xe365, + 0xe366, 0xe367, 0xe368, 0xe369, + 0xe36a, 0xe36b, 0xe36c, 0xe36d, + // F090 + 0xe36e, 0xe36f, 0xe370, 0xe371, + 0xe372, 0xe373, 0xe374, 0xe375, + 0xe376, 0xe377, 0xe378, 0xe379, + 0xe37a, 0xe37b, 0xe37c, 0xe37d, + // F0a0 + 0xe37e, 0xe37f, 0xe380, 0xe381, + 0xe382, 0xe383, 0xe384, 0xe385, + 0xe386, 0xe387, 0xe388, 0xe389, + 0xe38a, 0xe38b, 0xe38c, 0xe38d, + // F0b0 + 0xe38e, 0xe38f, 0xe390, 0xe391, + 0xe392, 0xe393, 0xe394, 0xe395, + 0xe396, 0xe397, 0xe398, 0xe399, + 0xe39a, 0xe39b, 0xe39c, 0xe39d, + // F0c0 + 0xe39e, 0xe39f, 0xe3a0, 0xe3a1, + 0xe3a2, 0xe3a3, 0xe3a4, 0xe3a5, + 0xe3a6, 0xe3a7, 0xe3a8, 0xe3a9, + 0xe3aa, 0xe3ab, 0xe3ac, 0xe3ad, + // F0d0 + 0xe3ae, 0xe3af, 0xe3b0, 0xe3b1, + 0xe3b2, 0xe3b3, 0xe3b4, 0xe3b5, + 0xe3b6, 0xe3b7, 0xe3b8, 0xe3b9, + 0xe3ba, 0xe3bb, 0xe3bc, 0xe3bd, + // F0e0 + 0xe3be, 0xe3bf, 0xe3c0, 0xe3c1, + 0xe3c2, 0xe3c3, 0xe3c4, 0xe3c5, + 0xe3c6, 0xe3c7, 0xe3c8, 0xe3c9, + 0xe3ca, 0xe3cb, 0xe3cd, 0xe3ce, + // F0f0 + 0xe3cf, 0xe3d0, 0xe3d1, 0xe3d2, + 0xe3d3, 0xe3d4, 0xe3d5, 0xe3d6, + 0xe3d7, 0xe3d8, 0xe3d9, 0xe3da, + 0xe3db, 0xe3dc, 0xe3dd, 0xe3de +}; + +// See http://www.iana.org/assignments/character-sets/character-sets.xml +// See ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/ADOBE/symbol.txt + +static const sal_Unicode aAdobeSymbolTab[224] = +{ +//TODO: + // F020 + 0x0020, 0xe100, 0xe101, 0xe102, + 0xe103, 0xe104, 0xe16a, 0xe105, + 0xe106, 0xe107, 0xe108, 0xe109, + 0xe10a, 0xe10b, 0xe10c, 0xe10d, + // F030 + 0x0030, 0x0031, 0x0032, 0x0033, + 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0xe10e, 0xe10f, + 0xe110, 0xe111, 0xe112, 0x003f, + // F040 + 0xe113, 0x0391, 0x0392, 0x03a7, + 0x0394, 0x0395, 0x03a6, 0x0393, + 0x0397, 0x0399, 0x03d1, 0x039a, + 0x039b, 0x039c, 0x039d, 0x039f, + // F050 + 0x03a0, 0x0398, 0x03a1, 0x03a3, + 0x03a4, 0x03a5, 0x03c2, 0x03a9, + 0x039e, 0x03a8, 0x0396, 0xe114, + 0x2234, 0xe115, 0xe116, 0x005f, + // F060 + 0x00af, 0x03b1, 0x03b2, 0x03c7, + 0x03b4, 0x03b5, 0x03d5, 0x03b3, + 0x03b7, 0x03b9, 0x03c6, 0x03ba, + 0x03bb, 0x03bc, 0x03bd, 0x03bf, + // F070 + 0x03c0, 0x03b8, 0x03c1, 0x03c3, + 0x03c4, 0x03c5, 0x03d6, 0x03c9, + 0x03be, 0x03c8, 0x03b6, 0xe117, + 0x007c, 0xe118, 0xe119, 0, + // F080 + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + // F090 + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + // F0a0 + 0xe11a, 0x03d2, 0x2032, 0xe11b, + 0x2215, 0xe11c, 0xe11d, 0xe11e, + 0x2666, 0xe11f, 0xe120, 0xe121, + 0xe122, 0xe123, 0xe124, 0xe125, + // F0b0 + 0xe126, 0xe127, 0x2033, 0xe128, + 0xe129, 0xe12a, 0xe12b, 0xe12c, + 0xe12d, 0xe12e, 0xe12f, 0xe130, + 0xe131, 0x2502, 0x2500, 0x21b2, + // F0c0 + 0xe132, 0xe133, 0xe134, 0xe135, + 0xe136, 0xe137, 0xe138, 0xe139, + 0xe13a, 0xe13b, 0xe13c, 0xe13d, + 0xe13e, 0xe13f, 0xe140, 0xe141, + // F0d0 + 0x2220, 0xe142, 0x00ae, 0x00a9, + 0xe143, 0xe144, 0xe145, 0xe146, + 0xe147, 0xe148, 0xe149, 0xe14a, + 0xe14b, 0x21d1, 0xe14c, 0x21d3, + // F0e0 + 0x25ca, 0xe14d, 0xe14e, 0xe14f, + 0xe150, 0xe151, 0xf8eb, 0xf8ec, + 0xf8ed, 0xf8ee, 0xf8ef, 0xf8f0, + 0xf8f1, 0xf8f2, 0xf8f3, 0xf8f4, + // F0f0 + 0, 0x232a, 0x222b, 0x2320, + 0xf8f5, 0x2321, 0xf8f6, 0xf8f7, + 0xf8f8, 0xf8f9, 0xf8fa, 0xf8fb, + 0xf8fc, 0xf8fd, 0xf8fe, 0, +}; + +static const sal_Unicode aMonotypeSortsTab[224] = +{ + // F020 + 0x0020, 0x2701, 0xe200, 0x2703, + 0x2704, 0xe201, 0x2706, 0xe202, + 0xe203, 0xe203, 0xe204, 0xe205, + 0x270c, 0xe206, 0xe207, 0xe208, + // F030 + 0x2710, 0x2711, 0x2712, 0xe209, + 0xe20a, 0x2715, 0x2716, 0xe20b, + 0xe20c, 0xe20d, 0xe20e, 0xe20f, + 0xe210, 0x271d, 0x271e, 0x271f, + // F040 + 0x2720, 0xe211, 0xe212, 0xe213, + 0xe214, 0xe215, 0x2726, 0x2727, + 0x2605, 0x2729, 0x272a, 0xe216, + 0xe217, 0xe218, 0xe219, 0xe21a, + // F050 + 0xe21b, 0xe21c, 0x2732, 0xe21d, + 0xe21e, 0xe21f, 0xe220, 0xe221, + 0xe222, 0xe223, 0x273a, 0x273b, + 0x273c, 0x273d, 0x273e, 0xe224, + // F060 + 0x2740, 0x2741, 0x2742, 0x2743, + 0xe225, 0x2745, 0x2746, 0x2747, + 0x2748, 0x2749, 0x274a, 0x274b, + 0xe226, 0xe227, 0xe228, 0xe229, + // F070 + 0xe22a, 0xe22b, 0xe22c, 0x25b2, + 0x25bc, 0xe22d, 0xe22e, 0xe22f, + 0x2758, 0xe230, 0x275a, 0x275b, + 0x275c, 0x275d, 0x275e, 0, + // F080 + 0xe231, 0xe232, 0xe233, 0xe234, + 0xe235, 0xe236, 0xe237, 0xe238, + 0xe239, 0xe23a, 0xe23b, 0xe23c, + 0xe23d, 0xe23e, 0, 0, + // F090 + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + // F0a0 + 0, 0xe23f, 0xe240, 0x2763, + 0x2764, 0x2765, 0x2766, 0x2767, + 0xe241, 0xe242, 0xe243, 0xe244, + 0x2460, 0x2461, 0x2462, 0x2463, + // F0b0 + 0x2464, 0x2465, 0x2466, 0x2467, + 0x2468, 0x2469, 0x2776, 0x2777, + 0x2778, 0x2779, 0x277a, 0x277b, + 0x277c, 0x277d, 0x277e, 0x277f, + // F0c0 + 0xe245, 0xe246, 0xe247, 0xe248, + 0xe249, 0xe24a, 0xe24b, 0xe24c, + 0xe24d, 0xe24e, 0xe24f, 0xe250, + 0xe251, 0xe252, 0xe253, 0xe254, + // F0d0 + 0xe255, 0xe256, 0xe257, 0xe258, + 0xe259, 0xe25a, 0xe25b, 0xe25c, + 0xe25d, 0x2799, 0xe25e, 0x279b, + 0x279c, 0x279d, 0x279e, 0x279f, + // F0e0 + 0x27a0, 0x27a1, 0xe25f, 0x27a3, + 0x27a4, 0x27a5, 0x27a6, 0x27a7, + 0x27a8, 0x27a9, 0x27aa, 0x27ab, + 0x27ac, 0x27ad, 0x27ae, 0x27af, + // F0f0 + 0, 0x27b1, 0xe260, 0x27b3, + 0x27b4, 0x27b5, 0x27b6, 0x27b7, + 0xe261, 0x27b9, 0x27ba, 0x27bb, + 0x27bc, 0x27bd, 0x27be, 0, +}; + +static const sal_Unicode aMTExtraTab[224] = +{ + // F020 + 0x0020, 0, 0, 0x0300, + 0x0302, 0x0303, 0x0307, 0, + 0x2323, 0x2322, 0, 0, + 0, 0, 0, 0, + // F030 + 0, 0xEC00, 0xEC01, 0xEC02, + 0xEC03, 0xEC0B, 0xEC04, 0xEC05, + 0xEC06, 0, 0x223C, 0x2243, + 0x22B2, 0x226A, 0x22B3, 0x226B, + // F040 + 0x225C, 0x2259, 0x2250, 0x2210, + 0x019B, 0xEC0E, 0xEC0F, 0xEC10, + 0xEC11, 0x2229, 0x2127, 0x2026, + 0x22EF, 0x22EE, 0x22F0, 0x22F1, + // F050 + 0x2225, 0x2235, 0x2221, 0x2222, + 0, 0x222A, 0x25B3, 0x25A1, + 0x25AD, 0x25B1, 0x2197, 0x2199, + 0xEB05, 0x2198, 0x2196, 0xEB06, + // F060 + 0x2035, 0x21A6, 0x2195, 0x21D5, + 0x25CB, 0x2299, 0x227B, 0xE98F, + 0x210F, 0xEE00, 0xEE01, 0, + 0x2113, 0x2213, 0xFFFD, 0x2218, + // F070 + 0x227A, 0xEB1A, 0x20D7, 0x20D6, + 0x20E1, 0xEB00, 0x20D1, 0x20D0, + 0xEB19, 0, 0, 0xFE38, + 0xEC0C, 0xFE37, 0xEC0D, 0, + // F080 + 0x21C4, 0xEB01, 0xEB02, 0x21CC, + 0xEB03, 0xEB04, 0x21C0, 0x21BD, + 0xF8E7, 0, 0, 0, + 0, 0, 0, 0, + // F090 + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + // F0a0 + 0, 0x211D, 0x2124, 0x2102, + 0x211A, 0x2115, 0, 0x301A, + 0x301B, 0xEC22, 0xEC23, 0xEC24, + 0xEC25, 0xEC26, 0xEC27, 0, + // F0b0 + 0xEE04, 0xEE05, 0xEE06, 0, + 0, 0xEE07, 0xEE08, 0xEE09, + 0, 0, 0xEE0A, 0xEE0B, + 0xEE0C, 0, 0, 0, + // F0c0 + 0xEE0D, 0xEE0E, 0xEE0F, 0xEE10, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + // F0d0 + 0, 0xEE11, 0xEE12, 0xEE13, + 0, 0xEE15, 0xEE16, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + // F0e0 + 0, 0, 0, 0, + 0, 0, 0, 0xF8FF, + 0x0160, 0x00DD, 0x00DE, 0x00D0, + 0x0161, 0x00FD, 0x00FE, 0x00F0, + // F0f0 + 0xFB01, 0xFB02, 0x0131, 0x00B9, + 0x00B2, 0x00B3, 0x00BD, 0x00BC, + 0x00BE, 0x2044, 0x00A6, 0x02DD, + 0x02D8, 0x02C7, 0x02DA, 0x02DB, +}; + +static const sal_Unicode aAdobeSymbolToAppleSymbolTab[224] = +{ + // F020 + 0x0020, 0x0021, 0x2200, 0x0023, + 0x2203, 0x0025, 0x0026, 0x220D, + 0x0028, 0x0029, 0x2217, 0x002B, + 0x002C, 0x2212, 0x002E, 0x002F, + // F030 + 0x0030, 0x0031, 0x0032, 0x0033, + 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, + 0x003C, 0x003D, 0x003E, 0x003F, + // F040 + 0x2245, 0x0391, 0x0392, 0x03A7, + 0x0394, 0x0395, 0x03A6, 0x0393, + 0x0397, 0x0399, 0x03D1, 0x039A, + 0x039B, 0x039C, 0x039D, 0x039F, + // F050 + 0x03A0, 0x0398, 0x03A1, 0x03A3, + 0x03A4, 0x03A5, 0x03C2, 0x03A9, + 0x039E, 0x03A8, 0x0396, 0x005B, + 0x2234, 0x005D, 0x22A5, 0x005F, + // F060 + 0xF8E5, 0x03B1, 0x03B2, 0x03C7, + 0x03B4, 0x03B5, 0x03C6, 0x03B3, + 0x03B7, 0x03B9, 0x03D5, 0x03BA, + 0x03BB, 0x03BC, 0x03BD, 0x03BF, + // F070 + 0x03C0, 0x03B8, 0x03C1, 0x03C3, + 0x03C4, 0x03C5, 0x03D6, 0x03C9, + 0x03BE, 0x03C8, 0x03B6, 0x007B, + 0x007C, 0x007D, 0x223C, 0x007F, + // F080 + 0x0080, 0x0081, 0x0082, 0x0083, + 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, + 0x008C, 0x008D, 0x008E, 0x008F, + // F090 + 0x0090, 0x0091, 0x0092, 0x0093, + 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, + 0x009C, 0x009D, 0x009E, 0x009F, + // F0a0 + 0x20AC, 0x03D2, 0x2032, 0x2264, + 0x2044, 0x221E, 0x0192, 0x2663, + 0x2666, 0x2665, 0x2660, 0x2194, + 0x2190, 0x2191, 0x2192, 0x2193, + // F0b0 + 0x00B0, 0x00B1, 0x2033, 0x2065, + 0x00D7, 0x221D, 0x2202, 0x2022, + 0x00F7, 0x2260, 0x2261, 0x2248, + 0x2026, 0x23D0, 0x23AF, 0x21B5, + // F0c0 + 0x2135, 0x2111, 0x211C, 0x2118, + 0x2297, 0x2295, 0x2205, 0x2229, + 0x222A, 0x2283, 0x2287, 0x2284, + 0x2282, 0x2286, 0x2208, 0x2209, + // F0d0 + 0x2220, 0x2207, 0x00AE, 0x00A9, + 0x2122, 0x220F, 0x221A, 0x22C5, + 0x00AC, 0x2227, 0x2228, 0x21D4, + 0x21D0, 0x21D1, 0x21D2, 0x21D3, + // F0e0 + 0x25CA, 0x3008, 0x00AE, 0x00A9, + 0x2122, 0x2211, 0x239B, 0x239C, + 0x239D, 0x23A1, 0x23A2, 0x23A3, + 0x23A7, 0x23A8, 0x23A9, 0x23AA, + // F0f0 + 0xF8FF, 0x3009, 0x222B, 0x2320, + 0x23AE, 0x2321, 0x239E, 0x239F, + 0x23A0, 0x23A4, 0x23A5, 0x23A6, + 0x23AB, 0x23AC, 0x23AD, 0x00FF +}; + +static sal_Unicode ImplStarSymbolToStarBats( sal_Unicode c ) +{ + switch ( c ) + { + case 0x00A2: c = 0xF0E0; break; + case 0x00A4: c = 0xF0E1; break; + case 0x00A5: c = 0xF0E2; break; + case 0x00A7: c = 0xF0A7; break; + case 0x00AB: c = 0xF0AB; break; + case 0x00B6: c = 0xF0DE; break; + case 0x00BB: c = 0xF0BB; break; + + case 0x0152: c = 0xF08C; break; + case 0x0153: c = 0xF09C; break; + case 0x0160: c = 0xF08A; break; + case 0x0161: c = 0xF09A; break; + case 0x0178: c = 0xF09F; break; + case 0x017D: c = 0xF08E; break; + case 0x017E: c = 0xF09E; break; + + case 0x0192: c = 0xF083; break; + case 0x02C6: c = 0xF088; break; + case 0x02DC: c = 0xF098; break; + case 0x2013: c = 0xF096; break; + case 0x2014: c = 0xF097; break; + case 0x2018: c = 0xF091; break; + + case 0x2019: c = 0xF092; break; + case 0x201A: c = 0xF082; break; + case 0x201C: c = 0xF093; break; + case 0x201D: c = 0xF094; break; + case 0x201E: c = 0xF084; break; + case 0x2020: c = 0xF086; break; + + case 0x2021: c = 0xF087; break; + case 0x2022: c = 0xF095; break; + case 0x2026: c = 0xF085; break; + case 0x2030: c = 0xF089; break; + case 0x2039: c = 0xF08B; break; + case 0x203A: c = 0xF09B; break; + + case 0x20A1: c = 0xF0E4; break; + case 0x20A2: c = 0xF0E5; break; + case 0x20A3: c = 0xF0E6; break; + case 0x20A4: c = 0xF0E7; break; + case 0x20A8: c = 0xF0EA; break; + case 0x20A9: c = 0xF0E8; break; + case 0x20AB: c = 0xF0E9; break; + case 0x20AC: c = 0xF080; break; + + case 0x2122: c = 0xF099; break; + case 0x2190: c = 0xF0B7; break; + case 0x2191: c = 0xF0B8; break; + case 0x2192: c = 0xF0B5; break; + case 0x2193: c = 0xF0B6; break; + case 0x2194: c = 0xF0D8; break; + case 0x2195: c = 0xF0D9; break; + + case 0x21E4: c = 0xF0B4; break; + case 0x21E5: c = 0xF0B3; break; + case 0x21E6: c = 0xF0A4; break; + case 0x21E7: c = 0xF0B2; break; + case 0x21E8: c = 0xF0AF; break; + case 0x21E9: c = 0xF0A3; break; + + case 0x25A0: c = 0xF024; break; + case 0x25A1: c = 0xF025; break; + case 0x25B4: c = 0xF0C5; break; + case 0x25B5: c = 0xF0C7; break; + case 0x25BE: c = 0xF0C4; break; + case 0x25BF: c = 0xF0C6; break; + case 0x25C6: c = 0xF043; break; + case 0x25CF: c = 0xF022; break; + case 0x25D7: c = 0xF0D0; break; + + case 0x260E: c = 0xF074; break; + case 0x2611: c = 0xF034; break; + case 0x2612: c = 0xF033; break; + case 0x261B: c = 0xF036; break; + case 0x261E: c = 0xF07D; break; + case 0x2639: c = 0xF0AD; break; + case 0x263A: c = 0xF021; break; + + case 0x2702: c = 0xF0CB; break; + case 0x2708: c = 0xF0CC; break; + case 0x270D: c = 0xF07E; break; + case 0x270E: c = 0xF038; break; + + case 0x2713: c = 0xF039; break; + case 0x2714: c = 0xF03A; break; + case 0x2717: c = 0xF04F; break; + case 0x2718: c = 0xF050; break; + case 0x2719: c = 0xF051; break; + case 0x271A: c = 0xF052; break; + case 0x271B: c = 0xF053; break; + case 0x271C: c = 0xF054; break; + + case 0x2721: c = 0xF0CD; break; + case 0x2722: c = 0xF044; break; + case 0x2723: c = 0xF045; break; + case 0x2724: c = 0xF046; break; + case 0x2725: c = 0xF047; break; + case 0x272B: c = 0xF055; break; + case 0x272C: c = 0xF056; break; + case 0x272D: c = 0xF057; break; + case 0x272E: c = 0xF058; break; + case 0x272F: c = 0xF059; break; + + case 0x2730: c = 0xF05A; break; + case 0x2733: c = 0xF048; break; + case 0x2734: c = 0xF049; break; + case 0x2735: c = 0xF04A; break; + case 0x2736: c = 0xF04B; break; + case 0x2737: c = 0xF04C; break; + case 0x2738: c = 0xF04D; break; + case 0x2739: c = 0xF04E; break; + case 0x273F: c = 0xF0CE; break; + + case 0x2744: c = 0xF0CF; break; + case 0x274D: c = 0xF023; break; + case 0x274F: c = 0xF03E; break; + case 0x2750: c = 0xF03F; break; + case 0x2751: c = 0xF027; break; + case 0x2752: c = 0xF028; break; + case 0x2756: c = 0xF02C; break; + case 0x2759: c = 0xF0D1; break; + case 0x2762: c = 0xF0D4; break; + + case 0x2780: c = 0xF068; break; + case 0x2781: c = 0xF069; break; + case 0x2782: c = 0xF06A; break; + case 0x2783: c = 0xF06B; break; + case 0x2784: c = 0xF06C; break; + case 0x2785: c = 0xF06D; break; + case 0x2786: c = 0xF06E; break; + case 0x2787: c = 0xF06F; break; + case 0x2788: c = 0xF070; break; + case 0x2789: c = 0xF071; break; + case 0x278A: c = 0xF05D; break; + case 0x278B: c = 0xF05E; break; + case 0x278C: c = 0xF05F; break; + case 0x278D: c = 0xF060; break; + case 0x278E: c = 0xF061; break; + case 0x278F: c = 0xF062; break; + + case 0x2790: c = 0xF063; break; + case 0x2791: c = 0xF064; break; + case 0x2792: c = 0xF065; break; + case 0x2793: c = 0xF066; break; + case 0x2794: c = 0xF031; break; + case 0x2798: c = 0xF0DA; break; + case 0x279A: c = 0xF0DB; break; + + case 0x27A2: c = 0xF02F; break; + case 0x27B2: c = 0xF035; break; + case 0x27B8: c = 0xF0DC; break; + + case 0xE000: c = 0xF000+38; break; + case 0xE001: c = 0xF000+41; break; + case 0xE002: c = 0xF000+42; break; + case 0xE003: c = 0xF000+43; break; + case 0xE004: c = 0xF000+45; break; + case 0xE005: c = 0xF000+46; break; + case 0xE006: c = 0xF000+48; break; + case 0xE007: c = 0xF000+57; break; + + case 0xE008: c = 0xF000+59; break; + case 0xE009: c = 0xF000+60; break; + case 0xE00a: c = 0xF000+61; break; + case 0xE00b: c = 0xF000+64; break; + case 0xE00c: c = 0xF000+65; break; + case 0xE00d: c = 0xF000+66; break; + case 0xE00e: c = 0xF000+67; break; + case 0xE00f: c = 0xF000+92; break; + + case 0xE010: c = 0xF000+103; break; + case 0xE011: c = 0xF000+114; break; + case 0xE012: c = 0xF000+115; break; + case 0xE013: c = 0xF000+117; break; + case 0xE014: c = 0xF000+118; break; + case 0xE015: c = 0xF000+119; break; + case 0xE016: c = 0xF000+120; break; + case 0xE017: c = 0xF000+121; break; + + case 0xE018: c = 0xF000+122; break; + case 0xE019: c = 0xF000+123; break; + case 0xE01a: c = 0xF000+124; break; + case 0xE01b: c = 0xF000+126; break; + case 0xE01c: c = 0xF000+136; break; + case 0xE01d: c = 0xF000+155; break; + case 0xE01e: c = 0xF000+165; break; + case 0xE01f: c = 0xF000+166; break; + + case 0xE020: c = 0xF000+168; break; + case 0xE021: c = 0xF000+169; break; + case 0xE022: c = 0xF000+170; break; + case 0xE023: c = 0xF000+172; break; + case 0xE024: c = 0xF000+174; break; + case 0xE025: c = 0xF000+175; break; + case 0xE026: c = 0xF000+176; break; + case 0xE027: c = 0xF000+177; break; + + case 0xE028: c = 0xF000+178; break; + case 0xE029: c = 0xF000+185; break; + case 0xE02a: c = 0xF000+186; break; + case 0xE02b: c = 0xF000+188; break; + case 0xE02c: c = 0xF000+189; break; + case 0xE02d: c = 0xF000+190; break; + case 0xE02e: c = 0xF000+191; break; + case 0xE02f: c = 0xF000+192; break; + + case 0xE030: c = 0xF000+193; break; + case 0xE031: c = 0xF000+194; break; + case 0xE032: c = 0xF000+195; break; + case 0xE033: c = 0xF000+200; break; + case 0xE034: c = 0xF000+201; break; + case 0xE035: c = 0xF000+202; break; + case 0xE036: c = 0xF000+210; break; + case 0xE037: c = 0xF000+211; break; + + case 0xE038: c = 0xF000+227; break; + case 0xE039: c = 0xF000+235; break; + case 0xE03a: c = 0xF000+255; break; + + default: c = 0; break; + } + + return c; +} + +namespace { + +enum SymbolFont +{ + Symbol=1, Wingdings=2, MonotypeSorts=4, Webdings=8, Wingdings2=16, + Wingdings3=32, MTExtra=64, TimesNewRoman=128 +}; + +} + +const char * const aSymbolNames[] = +{ + "Symbol", "Wingdings", "Monotype Sorts", "Webdings", "Wingdings 2", + "Wingdings 3", "MT Extra", "Times New Roman" +}; + +namespace { + +struct SymbolEntry +{ + sal_uInt8 cIndex; + enum SymbolFont eFont; +}; + +class StarSymbolToMSMultiFontImpl : public StarSymbolToMSMultiFont +{ +private: + ::std::multimap<sal_Unicode, SymbolEntry> maMagicMap; +public: + explicit StarSymbolToMSMultiFontImpl(); + OUString ConvertChar(sal_Unicode &rChar) override; +}; + +struct ExtraTable { sal_Unicode cStar; sal_uInt8 cMS;}; + +} + +ExtraTable const aWingDingsExtraTab[] = +{ + {0x25cf, 0x6C}, {0x2714, 0xFC}, {0x2717, 0xFB}, {0x2794, 0xE8}, + {0x27a2, 0xD8}, {0xe000, 0x6F}, {0xe001, 0x73}, {0xe002, 0x74}, + {0xe003, 0x75}, {0xe004, 0x77}, {0xe005, 0xA6}, {0xe006, 0xE0}, + {0xe007, 0xFC}, {0xe008, 0x6C}, {0xe009, 0x6D}, {0xe00a, 0x6E}, + {0xe00b, 0x72}, {0xe00c, 0x75}, {0xe00d, 0x76}, {0xe00e, 0x74}, + {0xe00f, 0x8B}, {0xe010, 0x80}, {0xe011, 0x2B}, {0xe012, 0x3A}, + {0xe013, 0x5D}, {0xe014, 0x29}, {0xe015, 0x3A}, {0xe016, 0x3C}, + {0xe017, 0x38}, {0xe018, 0x3A}, {0xe019, 0x2A}, {0xe01a, 0x2B}, + {0xe01b, 0x3F}, {0xe01c, 0x9F}, {0xe01d, 0x80}, {0xe01e, 0x8B}, + {0xe023, 0x4A}, {0xe025, 0xF0}, {0xe026, 0xF2}, {0xe027, 0xEF}, + {0xe028, 0xF1}, {0xe029, 0x52}, {0xe02a, 0x29}, {0xe02b, 0xE0}, + {0xe02c, 0xE2}, {0xe02d, 0xDF}, {0xe02e, 0xE1}, {0xe02f, 0xAC}, + {0xe030, 0xAD}, {0xe031, 0xAE}, {0xe032, 0x7C}, {0xe033, 0x43}, + {0xe034, 0x4D}, {0xe0aa, 0x71}, {0xe422, 0x44} +}; + +ExtraTable const aSymbolExtraTab2[] = +{ + {0x0020, 0x20}, {0x00A0, 0x20}, {0x0021, 0x21}, {0x2200, 0x22}, + {0x0023, 0x23}, {0x2203, 0x24}, {0x0025, 0x25}, {0x0026, 0x26}, + {0x220B, 0x27}, {0x0028, 0x28}, {0x0029, 0x29}, {0x2217, 0x2A}, + {0x002B, 0x2B}, {0x002C, 0x2C}, {0x2212, 0x2D}, {0x002E, 0x2E}, + {0x002F, 0x2F}, {0x003A, 0x3A}, {0x003B, 0x3B}, {0x003C, 0x3C}, + {0x003D, 0x3D}, {0x003E, 0x3E}, {0x2245, 0x40}, {0x2206, 0x44}, + {0x2126, 0x57}, {0x005B, 0x5B}, {0x005D, 0x5D}, {0x22A5, 0x5E}, + {0x03C6, 0x66}, {0x03D5, 0x6A}, {0x00B5, 0x6D}, {0x007B, 0x7B}, + {0x007C, 0x7C}, {0x007D, 0x7D}, {0x223C, 0x7E}, {0x20AC, 0xA0}, + {0x2032, 0xA2}, {0x2264, 0xA3}, {0x2044, 0xA4}, {0x221E, 0xA5}, + {0x0192, 0xA6}, {0x2663, 0xA7}, {0x2665, 0xA9}, {0x2660, 0xAA}, + {0x2194, 0xAB}, {0x2190, 0xAC}, {0x2191, 0xAD}, {0x2192, 0xAE}, + {0x2193, 0xAF}, {0x00B0, 0xB0}, {0x00B1, 0xB1}, {0x2265, 0xB3}, + {0x00D7, 0xB4}, {0x221D, 0xB5}, {0x2202, 0xB6}, {0x2022, 0xB7}, + {0x00F7, 0xB8}, {0x2260, 0xB9}, {0x2261, 0xBA}, {0x2248, 0xBB}, + {0x2026, 0xBC}, {0x21B5, 0xBF}, {0x2135, 0xC0}, {0x2111, 0xC1}, + {0x211C, 0xC2}, {0x2118, 0xC3}, {0x2297, 0xC4}, {0x2295, 0xC5}, + {0x2205, 0xC6}, {0x2229, 0xC7}, {0x222A, 0xC8}, {0x2283, 0xC9}, + {0x2287, 0xCA}, {0x2284, 0xCB}, {0x2282, 0xCC}, {0x2286, 0xCD}, + {0x2208, 0xCE}, {0x2209, 0xCF}, {0x2207, 0xD1}, {0x220F, 0xD5}, + {0x221A, 0xD6}, {0x22C5, 0xD7}, {0x00AC, 0xD8}, {0x2227, 0xD9}, + {0x2228, 0xDA}, {0x21D4, 0xDB}, {0x21D0, 0xDC}, {0x21D2, 0xDE}, + {0x2329, 0xE1}, {0x2211, 0xE5}, {0x232A, 0xF1}, {0x222B, 0xF2}, + {0x2320, 0xF3}, {0x2321, 0xF5}, {0x2013, 0x2D} +}; + +ExtraTable const aSymbolExtraTab[] = +{ + {0xe021, 0xD3}, {0xe024, 0xD2}, {0xe035, 0x20}, {0xe036, 0x28}, + {0xe037, 0x29}, {0xe039, 0x20}, {0xe083, 0x2B}, {0xe084, 0x3C}, + {0xe085, 0x3E}, {0xe086, 0xA3}, {0xe087, 0xB3}, {0xe089, 0xCE}, + {0xe08a, 0xA6}, {0xe08c, 0xAE}, {0xe08d, 0xD6}, {0xe08e, 0xD6}, + {0xe08f, 0xD6}, {0xe094, 0xA2}, {0xe09e, 0x28}, {0xe09f, 0x29}, + {0xe0a0, 0xD0}, {0xe0a6, 0xA2}, {0xe0a7, 0x7C}, {0xe0a8, 0x2F}, + {0xe0ab, 0x7C}, {0xe0ac, 0x47}, {0xe0ad, 0x44}, {0xe0ae, 0x51}, + {0xe0af, 0x4C}, {0xe0b0, 0x58}, {0xe0b1, 0x50}, {0xe0b2, 0x53}, + {0xe0b3, 0x55}, {0xe0b4, 0x46}, {0xe0b5, 0x59}, {0xe0b6, 0x57}, + {0xe0b7, 0x61}, {0xe0b8, 0x62}, {0xe0b9, 0x67}, {0xe0ba, 0x64}, + {0xe0bb, 0x65}, {0xe0bc, 0x7A}, {0xe0bd, 0x68}, {0xe0be, 0x71}, + {0xe0bf, 0x69}, {0xe0c0, 0x6B}, {0xe0c1, 0x6C}, {0xe0c2, 0x6D}, + {0xe0c3, 0x6E}, {0xe0c4, 0x78}, {0xe0c5, 0x6F}, {0xe0c6, 0x70}, + {0xe0c7, 0x72}, {0xe0c8, 0x73}, {0xe0c9, 0x74}, {0xe0ca, 0x75}, + {0xe0cb, 0x66}, {0xe0cc, 0x63}, {0xe0cd, 0x79}, {0xe0ce, 0x77}, + {0xe0cf, 0x65}, {0xe0d0, 0x4A}, {0xe0d1, 0x76}, {0xe0d3, 0x56}, + {0xe0d4, 0x6A}, {0xe0d5, 0xB6}, {0xe0d6, 0x69}, {0xe0db, 0xAC}, + {0xe0dc, 0xAD}, {0xe0dd, 0xAF} +}; + +ExtraTable const aTNRExtraTab[] = +{ + {0xe021, 0xA9}, + {0xe022, 0x40}, + {0xe024, 0xAE}, + {0xe035, 0x20}, + {0xe036, '('}, + {0xe037, ')'}, + {0xe039, 0x20}, + {0xe03a, 0x80}, + {0xe080, 0x89}, + {0xe083, '+'}, + {0xe084, '<'}, + {0xe085, '>'}, + {0xe0a9, '\\'} +}; + +StarSymbolToMSMultiFontImpl::StarSymbolToMSMultiFontImpl() +{ + struct ConvertTable + { + enum SymbolFont meFont; + const sal_Unicode* pTab; + }; + + //In order of preference + static const ConvertTable aConservativeTable[] = + { + {Symbol, aAdobeSymbolTab}, + {Wingdings, aWingDingsTab}, + {MonotypeSorts, aMonotypeSortsTab}, + {Webdings, aWebDingsTab}, + {Wingdings2, aWingDings2Tab}, + {Wingdings3, aWingDings3Tab}, + {MTExtra, aMTExtraTab} + }; + + struct ExtendedConvertTable + { + enum SymbolFont meFont; + const ExtraTable *mpTable; + size_t mnSize; + ExtendedConvertTable(SymbolFont eFont, const ExtraTable *pTable, + size_t nSize) + : meFont(eFont), mpTable(pTable), mnSize(nSize) {} + }; + + //Reverse map from a given starsymbol char to exact matches in ms symbol + //fonts. + int nEntries = SAL_N_ELEMENTS(aConservativeTable); + int i; + for (i = 0; i < nEntries; ++i) + { + const ConvertTable& r = aConservativeTable[i]; + SymbolEntry aEntry; + aEntry.eFont = r.meFont; + for (aEntry.cIndex = 0xFF; aEntry.cIndex >= 0x20; --aEntry.cIndex) + { + if (sal_Unicode cChar = r.pTab[aEntry.cIndex-0x20]) + maMagicMap.emplace(cChar, aEntry); + } + } + + //In order of preference + static const ExtendedConvertTable aAgressiveTable[] = + { + ExtendedConvertTable(Symbol, aSymbolExtraTab2, + sizeof(aSymbolExtraTab2)), + ExtendedConvertTable(Symbol, aSymbolExtraTab, + sizeof(aSymbolExtraTab)), + ExtendedConvertTable(Wingdings, aWingDingsExtraTab, + sizeof(aWingDingsExtraTab)), + ExtendedConvertTable(TimesNewRoman, aTNRExtraTab, + sizeof(aTNRExtraTab)) + }; + + //Allow extra conversions that are not perfect, but "good enough" + nEntries = SAL_N_ELEMENTS(aAgressiveTable); + + for (i = 0; i < nEntries; ++i) + { + const ExtendedConvertTable& r = aAgressiveTable[i]; + SymbolEntry aEntry; + aEntry.eFont = r.meFont; + for (int j = r.mnSize / sizeof(r.mpTable[0]) - 1; j >=0; --j) + { + aEntry.cIndex = r.mpTable[j].cMS; + maMagicMap.emplace(r.mpTable[j].cStar, aEntry); + } + } +} + +static const char *SymbolFontToString(int nResult) +{ + const char * const *ppName = aSymbolNames; + int nI = Symbol; + while (nI <= nResult) + { + if (!(nI & nResult)) + nI = nI << 1; + else + break; + ppName++; + } + return *ppName; +} + +OUString StarSymbolToMSMultiFontImpl::ConvertChar(sal_Unicode &rChar) +{ + OUString sRet; + + ::std::multimap<sal_Unicode, SymbolEntry>::const_iterator aResult = + maMagicMap.find(rChar); + + if (aResult != maMagicMap.end()) + { + const SymbolEntry &rEntry = (*aResult).second; + const char* pc = SymbolFontToString(rEntry.eFont); + sRet = OUString(pc, strlen(pc), RTL_TEXTENCODING_ASCII_US); + rChar = rEntry.cIndex; + } + + return sRet; +} + +StarSymbolToMSMultiFont *CreateStarSymbolToMSMultiFont() +{ + return new StarSymbolToMSMultiFontImpl; +} + +sal_Unicode ConvertChar::RecodeChar( sal_Unicode cChar ) const +{ + sal_Unicode cRetVal = 0; + if( mpCvtFunc ) + { + // use a conversion function for recoding + cRetVal = mpCvtFunc( cChar ); + } + else + { + // use a conversion table for recoding + sal_Unicode cIndex = cChar; + // allow symbol aliasing + if( cIndex & 0xFF00 ) + cIndex -= 0xF000; + // recode the symbol + if( cIndex>=0x0020 && cIndex<=0x00FF ) + { + cRetVal = mpCvtTab[ cIndex - 0x0020 ]; + + if (!cRetVal && mpSubsFontName) + { + if ( IsStarSymbol( OUString::createFromAscii(mpSubsFontName) ) ) + { + cRetVal = 0xE12C; + SAL_WARN( "unotools.misc", "Forcing a bullet substitution from 0x" << + OString::number(cChar, 16) << " to 0x" << + OString::number(cRetVal, 16)); + } + } + } + } + + return cRetVal ? cRetVal : cChar; +} + +// recode the string assuming the character codes are symbol codes +// from a traditional symbol font (i.e. U+F020..U+F0FF) +void ConvertChar::RecodeString( OUString& rStr, sal_Int32 nIndex, sal_Int32 nLen ) const +{ + sal_Int32 nLastIndex = nIndex + nLen; + OUStringBuffer aTmpStr(rStr); + + if( nLastIndex > aTmpStr.getLength() ) + nLastIndex = aTmpStr.getLength(); + + for(; nIndex < nLastIndex; ++nIndex ) + { + sal_Unicode cOrig = rStr[ nIndex ]; + // only recode symbols and their U+00xx aliases + if( ((cOrig < 0x0020) || (cOrig > 0x00FF)) + && ((cOrig < 0xF020) || (cOrig > 0xF0FF)) ) + continue; + + // recode a symbol + sal_Unicode cNew = RecodeChar( cOrig ); + if( cOrig != cNew ) + aTmpStr[ nIndex ] = cNew; + } + rStr = aTmpStr.makeStringAndClear(); +} + +namespace { + +struct RecodeTable { const char* pOrgName; ConvertChar aCvt;}; + +} + +static const RecodeTable aStarSymbolRecodeTable[] = +{ + // the first two entries must be StarMath and StarBats; do not reorder! + // reason: see CreateFontToSubsFontConverter method + {"starbats", {aStarBatsTab, "StarSymbol", nullptr}}, + {"starmath", {aStarMathTab, "StarSymbol", nullptr}}, + + {"symbol", {aAdobeSymbolTab, "StarSymbol", nullptr}}, + {"standardsymbols", {aAdobeSymbolTab, "StarSymbol", nullptr}}, + {"standardsymbolsl",{aAdobeSymbolTab, "StarSymbol", nullptr}}, + + {"monotypesorts", {aMonotypeSortsTab, "StarSymbol", nullptr}}, +// {"monotypesorts2", {aMonotypeSorts2Tab, "StarSymbol", NULL}} + {"zapfdingbats", {aMonotypeSortsTab, "StarSymbol", nullptr}}, //ZapfDingbats=MonotypeSorts-X? + {"itczapfdingbats", {aMonotypeSortsTab, "StarSymbol", nullptr}}, + {"dingbats", {aMonotypeSortsTab, "StarSymbol", nullptr}}, + + {"webdings", {aWebDingsTab, "StarSymbol", nullptr}}, + {"wingdings", {aWingDingsTab, "StarSymbol", nullptr}}, + {"wingdings2", {aWingDings2Tab, "StarSymbol", nullptr}}, + {"wingdings3", {aWingDings3Tab, "StarSymbol", nullptr}}, + {"mtextra", {aMTExtraTab, "StarSymbol", nullptr}} +}; + +static const RecodeTable aAppleSymbolRecodeTable[] = { + {"symbol", {aAdobeSymbolToAppleSymbolTab, "AppleSymbol", nullptr}} +}; + +static ConvertChar aImplStarSymbolCvt = { nullptr, "StarBats", ImplStarSymbolToStarBats }; + +const ConvertChar* ConvertChar::GetRecodeData( const OUString& rOrgFontName, const OUString& rMapFontName ) +{ + const ConvertChar* pCvt = nullptr; + + // clean up and lowercase font name + OUString aOrgName( GetEnglishSearchFontName( rOrgFontName ) ); + OUString aMapName( GetEnglishSearchFontName( rMapFontName ) ); + + if( aMapName == "starsymbol" + || aMapName == "opensymbol" ) + { + for( int i = 0; i < int(SAL_N_ELEMENTS(aStarSymbolRecodeTable)); ++i) + { + const RecodeTable& r = aStarSymbolRecodeTable[i]; + if( aOrgName.equalsAscii( r.pOrgName ) ) + { + pCvt = &r.aCvt; + break; + } + } + } + //It's plausible that it's better to implement this + //as an additional encoding alongside the existing + //adobe-symbol to unicode conversion in rtl instead + else if( aMapName == "applesymbol" ) + { + for( int i = 0; i < int(SAL_N_ELEMENTS(aAppleSymbolRecodeTable)); ++i) + { + const RecodeTable& r = aAppleSymbolRecodeTable[i]; + if( aOrgName.equalsAscii( r.pOrgName ) ) + { + pCvt = &r.aCvt; + break; + } + } + } + else if( aMapName == "starbats" ) + { + if( aOrgName == "starsymbol" ) + pCvt = &aImplStarSymbolCvt; + else if( aOrgName == "opensymbol" ) + pCvt = &aImplStarSymbolCvt; + } + + return pCvt; +} + +FontToSubsFontConverter CreateFontToSubsFontConverter( const OUString& rOrgName, FontToSubsFontFlags nFlags ) +{ + const ConvertChar* pCvt = nullptr; + + OUString aName = GetEnglishSearchFontName( rOrgName ); + + if ( nFlags == FontToSubsFontFlags::IMPORT ) + { + const int nEntries = 2; // only StarMath+StarBats + for( int i = 0; i < nEntries; ++i ) + { + const RecodeTable& r = aStarSymbolRecodeTable[i]; + if( aName.equalsAscii( r.pOrgName ) ) + { + pCvt = &r.aCvt; + break; + } + } + } + else + { + // TODO: only StarMath+StarBats + if( aName == "starsymbol" ) + pCvt = &aImplStarSymbolCvt; + else if( aName == "opensymbol" ) + pCvt = &aImplStarSymbolCvt; + } + + return const_cast<ConvertChar *>(pCvt); +} + +sal_Unicode ConvertFontToSubsFontChar( + FontToSubsFontConverter hConverter, sal_Unicode cChar ) +{ + if ( hConverter ) + return static_cast<ConvertChar*>(hConverter)->RecodeChar( cChar ); + else + return cChar; +} + +OUString GetFontToSubsFontName( FontToSubsFontConverter hConverter ) +{ + if ( !hConverter ) + return OUString(); + + const char* pName = static_cast<ConvertChar*>(hConverter)->mpSubsFontName; + return OUString::createFromAscii( pName ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/misc/fontdefs.cxx b/unotools/source/misc/fontdefs.cxx new file mode 100644 index 000000000..3eb4d69bd --- /dev/null +++ b/unotools/source/misc/fontdefs.cxx @@ -0,0 +1,560 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <unotools/fontdefs.hxx> +#include <unotools/fontcfg.hxx> +#include <rtl/ustrbuf.hxx> +#include <unordered_map> + +namespace { + +struct ImplLocalizedFontName +{ + const char* mpEnglishName; + const sal_Unicode* mpLocalizedNames; +}; + +} + +// TODO: where did the 0,0 delimiters come from? A single 0 should suffice... +static sal_Unicode const aBatang[] = { 0xBC14, 0xD0D5, 0, 0 }; +static sal_Unicode const aBatangChe[] = { 0xBC14, 0xD0D5, 0xCCB4, 0, 0 }; +static sal_Unicode const aGungsuh[] = { 0xAD81, 0xC11C, 0, 0 }; +static sal_Unicode const aGungsuhChe[] = { 0xAD81, 0xC11C, 0xCCB4, 0, 0 }; +static sal_Unicode const aGulim[] = { 0xAD74, 0xB9BC, 0, 0 }; +static sal_Unicode const aGulimChe[] = { 0xAD74, 0xB9BC, 0xCCB4, 0, 0 }; +static sal_Unicode const aDotum[] = { 0xB3CB, 0xC6C0, 0, 0 }; +static sal_Unicode const aDotumChe[] = { 0xB3CB, 0xC6C0, 0xCCB4, 0, 0 }; +static sal_Unicode const aSimSun[] = { 0x5B8B, 0x4F53, 0, 0 }; +static sal_Unicode const aNSimSun[] = { 0x65B0, 0x5B8B, 0x4F53, 0, 0 }; +static sal_Unicode const aSimHei[] = { 0x9ED1, 0x4F53, 0, 0 }; +static sal_Unicode const aSimKai[] = { 0x6977, 0x4F53, 0, 0 }; +static sal_Unicode const azycjkSun[] = { 0x4E2D, 0x6613, 0x5B8B, 0x4F53, 0, 0 }; +static sal_Unicode const azycjkHei[] = { 0x4E2D, 0x6613, 0x9ED1, 0x4F53, 0, 0 }; +static sal_Unicode const azycjkKai[] = { 0x4E2D, 0x6613, 0x6977, 0x4F53, 0, 0 }; +static sal_Unicode const aFZHei[] = { 0x65B9, 0x6B63, 0x9ED1, 0x4F53, 0, 0 }; +static sal_Unicode const aFZKai[] = { 0x65B9, 0x6B63, 0x6977, 0x4F53, 0, 0 }; +static sal_Unicode const aFZSongYI[] = { 0x65B9, 0x6B63, 0x5B8B, 0x4E00, 0, 0 }; +static sal_Unicode const aFZShuSong[] = { 0x65B9, 0x6B63, 0x4E66, 0x5B8B, 0, 0 }; +static sal_Unicode const aFZFangSong[] = { 0x65B9, 0x6B63, 0x4EFF, 0x5B8B, 0, 0 }; +// Attention: this fonts includes the wrong encoding vector - so we double the names with correct and wrong encoding +// First one is the GB-Encoding (we think the correct one), second is the big5 encoded name +static sal_Unicode const aMHei[] = { 'm', 0x7B80, 0x9ED1, 0, 'm', 0x6F60, 0x7AAA, 0, 0 }; +static sal_Unicode const aMKai[] = { 'm', 0x7B80, 0x6977, 0x566C, 0, 'm', 0x6F60, 0x7FF1, 0x628E, 0, 0 }; +static sal_Unicode const aMSong[] = { 'm', 0x7B80, 0x5B8B, 0, 'm', 0x6F60, 0x51BC, 0, 0 }; +static sal_Unicode const aCFangSong[] = { 'm', 0x7B80, 0x592B, 0x5B8B, 0, 'm', 0x6F60, 0x6E98, 0x51BC, 0, 0 }; +static sal_Unicode const aMingLiU[] = { 0x7D30, 0x660E, 0x9AD4, 0, 0 }; +static sal_Unicode const aPMingLiU[] = { 0x65B0, 0x7D30, 0x660E, 0x9AD4, 0, 0 }; +static sal_Unicode const aHei[] = { 0x6865, 0, 0 }; +static sal_Unicode const aKai[] = { 0x6B61, 0, 0 }; +static sal_Unicode const aMing[] = { 0x6D69, 0x6E67, 0, 0 }; +static sal_Unicode const aMSGothic[] = { 'm','s', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 }; +static sal_Unicode const aMSPGothic[] = { 'm','s','p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 }; +static sal_Unicode const aMSMincho[] = { 'm', 's', 0x660E, 0x671D, 0 }; +static sal_Unicode const aMSPMincho[] = { 'm','s','p', 0x660E, 0x671D, 0 }; +static sal_Unicode const aMSYaHei[] = { 0x5FAE, 0x8F6F, 0x96C5, 0x9ED1, 0 }; +static sal_Unicode const aMSJhengHei[] = { 0x5FAE, 0x8EDF, 0x6B63, 0x9ED1, 0x9AD4, 0 }; +static sal_Unicode const aMeiryo[] = { 0x30e1, 0x30a4, 0x30ea, 0x30aa, 0 }; +static sal_Unicode const aHGMinchoL[] = { 'h','g', 0x660E, 0x671D, 'l', 0, 0 }; +static sal_Unicode const aHGGothicB[] = { 'h','g', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 0 }; +static sal_Unicode const aHGPMinchoL[] = { 'h','g','p', 0x660E, 0x671D, 'l', 0 }; +static sal_Unicode const aHGPGothicB[] = { 'h','g','p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 0 }; +static sal_Unicode const aHGMinchoLSun[] = { 'h','g', 0x660E, 0x671D, 'l', 's', 'u', 'n', 0 }; +static sal_Unicode const aHGPMinchoLSun[] = { 'h','g','p', 0x660E, 0x671D, 'l', 's', 'u', 'n', 0 }; +static sal_Unicode const aHGGothicBSun[] = { 'h', 'g', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 's', 'u', 'n', 0 }; +static sal_Unicode const aHGPGothicBSun[] = { 'h', 'g', 'p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 's', 'u', 'n', 0 }; +static sal_Unicode const aHGHeiseiMin[] = { 'h', 'g', 0x5E73, 0x6210, 0x660E, 0x671D, 0x4F53, 0, 'h', 'g', 0x5E73, 0x6210, 0x660E, 0x671D, 0x4F53, 'w', '3', 'x', '1', '2', 0, 0 }; +static sal_Unicode const aIPAMincho[] = { 'i', 'p', 'a', 0x660E, 0x671D, 0 }; +static sal_Unicode const aIPAPMincho[] = { 'i', 'p', 'a', 'p', 0x660E, 0x671D, 0 }; +static sal_Unicode const aIPAGothic[] = { 'i', 'p', 'a', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 }; +static sal_Unicode const aIPAPGothic[] = { 'i', 'p', 'a', 'p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 }; +static sal_Unicode const aIPAUIGothic[] = { 'i', 'p', 'a', 'u', 'i', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 }; +static sal_Unicode const aTakaoMincho[] = { 't', 'a', 'k', 'a', 'o', 0x660E, 0x671D, 0 }; +static sal_Unicode const aTakaoPMincho[] = { 't', 'a', 'k', 'a', 'o', 'p', 0x660E, 0x671D, 0 }; +static sal_Unicode const aTakaoGothic[] = { 't', 'a', 'k', 'a', 'o', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 }; +static sal_Unicode const aTakaoPGothic[] = { 't', 'a', 'k', 'a', 'o', 'p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 }; +static sal_Unicode const aSazanamiMincho[] = { 0x3055, 0x3056, 0x306A, 0x307F, 0x660E, 0x671D, 0, 0 }; +static sal_Unicode const aSazanamiGothic[] = { 0x3055, 0x3056, 0x306A, 0x307F, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 }; +static sal_Unicode const aKochiMincho[] = { 0x6771, 0x98A8, 0x660E, 0x671D, 0, 0 }; +static sal_Unicode const aKochiGothic[] = { 0x6771, 0x98A8, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 }; +static sal_Unicode const aSunDotum[] = { 0xC36C, 0xB3CB, 0xC6C0, 0, 0 }; +static sal_Unicode const aSunGulim[] = { 0xC36C, 0xAD74, 0xB9BC, 0, 0 }; +static sal_Unicode const aSunBatang[] = { 0xC36C, 0xBC14, 0xD0D5, 0, 0 }; +static sal_Unicode const aBaekmukDotum[] = { 0xBC31, 0xBB35, 0xB3CB, 0xC6C0, 0, 0 }; +static sal_Unicode const aBaekmukGulim[] = { 0xBC31, 0xBB35, 0xAD74, 0xB9BC, 0, 0 }; +static sal_Unicode const aBaekmukBatang[] = { 0xBC31, 0xBB35, 0xBC14, 0xD0D5, 0, 0 }; +static sal_Unicode const aFzMingTi[] = { 0x65B9, 0x6B63, 0x660E, 0x9AD4, 0, 0 }; +static sal_Unicode const aFzHeiTiTW[]= { 0x65B9, 0x6B63, 0x9ED1, 0x9AD4, 0, 0 }; +static sal_Unicode const aFzKaiTiTW[]= { 0x65B9, 0x6B63, 0x6977, 0x9AD4, 0, 0 }; +static sal_Unicode const aFzHeiTiCN[]= { 0x65B9, 0x6B63, 0x9ED1, 0x4F53, 0, 0 }; +static sal_Unicode const aFzKaiTiCN[]= { 0x65B9, 0x6B63, 0x6977, 0x4F53, 0, 0 }; +static sal_Unicode const aFzSongTi[] = { 0x65B9, 0x6B63, 0x5B8B, 0x4F53, 0, 0 }; +static sal_Unicode const aHYMyeongJoExtra[] = { 'h', 'y', 0xACAC, 0xBA85, 0xC870, 0, 0 }; +static sal_Unicode const aHYSinMyeongJoMedium[] = { 'h', 'y', 0xC2E0, 0xBA85, 0xC870, 0, 0 }; +static sal_Unicode const aHYGothicMedium[] = { 'h', 'y', 0xC911, 0xACE0, 0xB515, 0, 0 }; +static sal_Unicode const aHYGraphicMedium[] = { 'h', 'y', 0xADF8, 0xB798, 0xD53D, 'm', 0, 0 }; +static sal_Unicode const aHYGraphic[] = { 'h', 'y', 0xADF8, 0xB798, 0xD53D, 0, 0 }; +static sal_Unicode const aNewGulim[] = { 0xC0C8, 0xAD74, 0xB9BC, 0, 0 }; +static sal_Unicode const aSunGungseo[] = { 0xC36C, 0xAD81, 0xC11C, 0, 0 }; +static sal_Unicode const aHYGungSoBold[] = { 'h','y', 0xAD81, 0xC11C, 'b', 0, 0 }; +static sal_Unicode const aHYGungSo[] = { 'h','y', 0xAD81, 0xC11C, 0, 0 }; +static sal_Unicode const aSunHeadLine[] = { 0xC36C, 0xD5E4, 0xB4DC, 0xB77C, 0xC778, 0, 0 }; +static sal_Unicode const aHYHeadLineMedium[] = { 'h', 'y', 0xD5E4, 0xB4DC, 0xB77C, 0xC778, 'm', 0, 0 }; +static sal_Unicode const aHYHeadLine[] = { 'h', 'y', 0xD5E4, 0xB4DC, 0xB77C, 0xC778, 0, 0 }; +static sal_Unicode const aYetR[] = { 0xD734, 0xBA3C, 0xC61B, 0xCCB4, 0, 0 }; +static sal_Unicode const aHYGothicExtra[] = { 'h', 'y', 0xACAC, 0xACE0, 0xB515, 0, 0 }; +static sal_Unicode const aSunMokPan[] = { 0xC36C, 0xBAA9, 0xD310, 0, 0 }; +static sal_Unicode const aSunYeopseo[] = { 0xC36C, 0xC5FD, 0xC11C, 0, 0 }; +static sal_Unicode const aSunBaekSong[] = { 0xC36C, 0xBC31, 0xC1A1, 0, 0 }; +static sal_Unicode const aHYPostLight[] = { 'h', 'y', 0xC5FD, 0xC11C, 'l', 0, 0 }; +static sal_Unicode const aHYPost[] = { 'h', 'y', 0xC5FD, 0xC11C, 0, 0 }; +static sal_Unicode const aMagicR[] = { 0xD734, 0xBA3C, 0xB9E4, 0xC9C1, 0xCCB4, 0, 0 }; +static sal_Unicode const aSunCrystal[] = { 0xC36C, 0xD06C, 0xB9AC, 0xC2A4, 0xD0C8, 0, 0 }; +static sal_Unicode const aSunSaemmul[] = { 0xC36C, 0xC0D8, 0xBB3C, 0, 0 }; +static sal_Unicode const aHaansoftBatang[] = { 0xD55C, 0xCEF4, 0xBC14, 0xD0D5, 0, 0 }; +static sal_Unicode const aHaansoftDotum[] = { 0xD55C, 0xCEF4, 0xB3CB, 0xC6C0, 0, 0 }; +static sal_Unicode const aHyhaeseo[] = { 0xD55C, 0xC591, 0xD574, 0xC11C, 0, 0 }; +static sal_Unicode const aMDSol[] = { 'm', 'd', 0xC194, 0xCCB4, 0, 0 }; +static sal_Unicode const aMDGaesung[] = { 'm', 'd', 0xAC1C, 0xC131, 0xCCB4, 0, 0 }; +static sal_Unicode const aMDArt[] = { 'm', 'd', 0xC544, 0xD2B8, 0xCCB4, 0, 0 }; +static sal_Unicode const aMDAlong[] = { 'm', 'd', 0xC544, 0xB871, 0xCCB4, 0, 0 }; +static sal_Unicode const aMDEasop[] = { 'm', 'd', 0xC774, 0xC19D, 0xCCB4, 0, 0 }; +static sal_Unicode const aHYShortSamulMedium[] = { 'h', 'y', 0xC595, 0xC740, 0xC0D8, 0xBB3C, 'm', 0 }; +static sal_Unicode const aHYShortSamul[] = { 'h', 'y', 0xC595, 0xC740, 0xC0D8, 0xBB3C, 0 }; +static sal_Unicode const aHGGothicE[] = { 'h','g', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'e', 0 }; +static sal_Unicode const aHGPGothicE[] = { 'h','g','p', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'e', 0 }; +static sal_Unicode const aHGSGothicE[] = { 'h','g','s', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'e', 0 }; +static sal_Unicode const aHGGothicM[] = { 'h','g', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'm', 0 }; +static sal_Unicode const aHGPGothicM[] = { 'h','g','p', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'm', 0 }; +static sal_Unicode const aHGSGothicM[] = { 'h','g','s', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'm', 0 }; +static sal_Unicode const aHGGyoshotai[] = { 'h','g', 0x884C, 0x66F8, 0x4F53, 0 }; +static sal_Unicode const aHGPGyoshotai[] = { 'h','g','p', 0x884C, 0x66F8, 0x4F53, 0 }; +static sal_Unicode const aHGSGyoshotai[] = { 'h','g','s', 0x884C, 0x66F8, 0x4F53, 0 }; +static sal_Unicode const aHGKyokashotai[] = { 'h','g', 0x6559, 0x79D1, 0x66F8, 0x4F53, 0 }; +static sal_Unicode const aHGPKyokashotai[] = { 'h','g','p', 0x6559, 0x79D1, 0x66F8, 0x4F53, 0 }; +static sal_Unicode const aHGSKyokashotai[] = { 'h','g','s', 0x6559, 0x79D1, 0x66F8, 0x4F53, 0 }; +static sal_Unicode const aHGMinchoB[] = { 'h','g', 0x660E, 0x671D, 'b', 0 }; +static sal_Unicode const aHGPMinchoB[] = { 'h','g','p', 0x660E, 0x671D, 'b', 0 }; +static sal_Unicode const aHGSMinchoB[] = { 'h','g','s', 0x660E, 0x671D, 'b', 0 }; +static sal_Unicode const aHGMinchoE[] = { 'h','g', 0x660E, 0x671D, 'e', 0 }; +static sal_Unicode const aHGPMinchoE[] = { 'h','g','p', 0x660E, 0x671D, 'e', 0 }; +static sal_Unicode const aHGSMinchoE[] = { 'h','g','s', 0x660E, 0x671D, 'e', 0 }; +static sal_Unicode const aHGSoeiKakupoptai[] = { 'h','g', 0x5275,0x82F1,0x89D2,0xFF8E, + 0xFF9F,0xFF6F,0xFF8C,0xFF9F,0x4F53,0}; +static sal_Unicode const aHGPSoeiKakupoptai[] = { 'h','g', 'p', 0x5275,0x82F1,0x89D2,0xFF8E, + 0xFF9F,0xFF6F,0xFF8C,0xFF9F,0x4F53,0}; +static sal_Unicode const aHGSSoeiKakupoptai[] = { 'h','g', 's', 0x5275,0x82F1,0x89D2,0xFF8E, + 0xFF9F,0xFF6F,0xFF8C,0xFF9F,0x4F53,0}; +static sal_Unicode const aHGSoeiPresenceEB[] = { 'h','g', 0x5275,0x82F1,0xFF8C,0xFF9F, + 0xFF9A,0xFF7E,0xFF9E,0xFF9D,0xFF7D, 'e','b',0}; +static sal_Unicode const aHGPSoeiPresenceEB[] = { 'h','g','p', 0x5275,0x82F1,0xFF8C,0xFF9F, + 0xFF9A,0xFF7E,0xFF9E,0xFF9D,0xFF7D, 'e','b',0}; +static sal_Unicode const aHGSSoeiPresenceEB[] = { 'h','g','s', 0x5275,0x82F1,0xFF8C,0xFF9F, + 0xFF9A,0xFF7E,0xFF9E,0xFF9D,0xFF7D, 'e','b',0}; +static sal_Unicode const aHGSoeiKakugothicUB[] = { 'h','g', 0x5275,0x82F1,0x89D2,0xFF7A, + 0xFF9E,0xFF7C,0xFF6F,0xFF78,'u','b',0}; +static sal_Unicode const aHGPSoeiKakugothicUB[] = { 'h','g','p', 0x5275,0x82F1,0x89D2,0xFF7A, + 0xFF9E,0xFF7C,0xFF6F,0xFF78,'u','b',0}; +static sal_Unicode const aHGSSoeiKakugothicUB[] = { 'h','g','s', 0x5275,0x82F1,0x89D2,0xFF7A, + 0xFF9E,0xFF7C,0xFF6F,0xFF78,'u','b',0}; +static sal_Unicode const aHGSeikaishotaiPRO[] = { 'h','g', 0x6B63,0x6977,0x66F8,0x4F53, '-','p','r','o',0}; +static sal_Unicode const aHGMaruGothicMPRO[] = { 'h','g', 0x4E38,0xFF7A,0xFF9E,0xFF7C,0xFF6F,0xFF78, '-','p','r','o',0}; +static sal_Unicode const aHiraginoMinchoPro[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x660E, 0x671D, 'p','r','o',0}; +static sal_Unicode const aHiraginoMinchoProN[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x660E, 0x671D, 'p','r','o','n',0}; +static sal_Unicode const aHiraginoKakuGothic[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x89D2, 0x30B4, 0x30B7, 0x30C3, 0x30AF,0}; +static sal_Unicode const aHiraginoKakuGothicPro[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x89D2, 0x30B4, 'p','r','o',0}; +static sal_Unicode const aHiraginoKakuGothicProN[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x89D2, 0x30B4, 'p','r','o','n',0}; +static sal_Unicode const aHiraginoMaruGothicPro[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x4E38, 0x30B4, 'p','r','o',0}; +static sal_Unicode const aHiraginoMaruGothicProN[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x4E38, 0x30B4, 'p','r','o','n',0}; + +static const ImplLocalizedFontName aImplLocalizedNamesList[] = +{ +{ "batang", aBatang }, +{ "batangche", aBatangChe }, +{ "gungshu", aGungsuh }, +{ "gungshuche", aGungsuhChe }, +{ "gulim", aGulim }, +{ "gulimche", aGulimChe }, +{ "dotum", aDotum }, +{ "dotumche", aDotumChe }, +{ "simsun", aSimSun }, +{ "nsimsun", aNSimSun }, +{ "simhei", aSimHei }, +{ "simkai", aSimKai }, +{ "zycjksun", azycjkSun }, +{ "zycjkhei", azycjkHei }, +{ "zycjkkai", azycjkKai }, +{ "fzhei", aFZHei }, +{ "fzkai", aFZKai }, +{ "fzsong", aFZSongYI }, +{ "fzshusong", aFZShuSong }, +{ "fzfangsong", aFZFangSong }, +{ "mhei", aMHei }, +{ "mkai", aMKai }, +{ "msong", aMSong }, +{ "cfangsong", aCFangSong }, +{ "mingliu", aMingLiU }, +{ "pmingliu", aPMingLiU }, +{ "hei", aHei }, +{ "kai", aKai }, +{ "ming", aMing }, +{ "msgothic", aMSGothic }, +{ "mspgothic", aMSPGothic }, +{ "msmincho", aMSMincho }, +{ "mspmincho", aMSPMincho }, +{ "microsoftjhenghei", aMSJhengHei }, +{ "microsoftyahei", aMSYaHei }, +{ "meiryo", aMeiryo }, +{ "hgminchol", aHGMinchoL }, +{ "hggothicb", aHGGothicB }, +{ "hgpminchol", aHGPMinchoL }, +{ "hgpgothicb", aHGPGothicB }, +{ "hgmincholsun", aHGMinchoLSun }, +{ "hggothicbsun", aHGGothicBSun }, +{ "hgpmincholsun", aHGPMinchoLSun }, +{ "hgpgothicbsun", aHGPGothicBSun }, +{ "hgheiseimin", aHGHeiseiMin }, +{ "ipamincho", aIPAMincho }, +{ "ipapmincho", aIPAPMincho }, +{ "ipagothic", aIPAGothic }, +{ "ipapgothic", aIPAPGothic }, +{ "ipauigothic", aIPAUIGothic }, +{ "takaomincho", aTakaoMincho }, +{ "takaopmincho", aTakaoPMincho }, +{ "takaogothic", aTakaoGothic }, +{ "takaopgothic", aTakaoPGothic }, +{ "sazanamimincho", aSazanamiMincho }, +{ "sazanamigothic", aSazanamiGothic }, +{ "kochimincho", aKochiMincho }, +{ "kochigothic", aKochiGothic }, +{ "sundotum", aSunDotum }, +{ "sungulim", aSunGulim }, +{ "sunbatang", aSunBatang }, +{ "baekmukdotum", aBaekmukDotum }, +{ "baekmukgulim", aBaekmukGulim }, +{ "baekmukbatang", aBaekmukBatang }, +{ "fzheiti", aFzHeiTiCN }, +{ "fzheiti", aFzHeiTiTW }, +{ "fzkaiti", aFzKaiTiCN }, +{ "fzkaitib", aFzKaiTiTW }, +{ "fzmingtib", aFzMingTi }, +{ "fzsongti", aFzSongTi }, +{ "hymyeongjoextra", aHYMyeongJoExtra }, +{ "hysinmyeongjomedium", aHYSinMyeongJoMedium }, +{ "hygothicmedium", aHYGothicMedium }, +{ "hygraphicmedium", aHYGraphicMedium }, +{ "hygraphic", aHYGraphic }, +{ "newgulim", aNewGulim }, +{ "sungungseo", aSunGungseo }, +{ "hygungsobold", aHYGungSoBold }, +{ "hygungso", aHYGungSo }, +{ "sunheadline", aSunHeadLine }, +{ "hyheadlinemedium", aHYHeadLineMedium }, +{ "hyheadline", aHYHeadLine }, +{ "yetr", aYetR }, +{ "hygothicextra", aHYGothicExtra }, +{ "sunmokpan", aSunMokPan }, +{ "sunyeopseo", aSunYeopseo }, +{ "sunbaeksong", aSunBaekSong }, +{ "hypostlight", aHYPostLight }, +{ "hypost", aHYPost }, +{ "magicr", aMagicR }, +{ "suncrystal", aSunCrystal }, +{ "sunsaemmul", aSunSaemmul }, +{ "hyshortsamulmedium", aHYShortSamulMedium }, +{ "hyshortsamul", aHYShortSamul }, +{ "haansoftbatang", aHaansoftBatang }, +{ "haansoftdotum", aHaansoftDotum }, +{ "hyhaeseo", aHyhaeseo }, +{ "mdsol", aMDSol }, +{ "mdgaesung", aMDGaesung }, +{ "mdart", aMDArt }, +{ "mdalong", aMDAlong }, +{ "mdeasop", aMDEasop }, +{ "hggothice", aHGGothicE }, +{ "hgpgothice", aHGPGothicE }, +{ "hgsgothice", aHGSGothicE }, +{ "hggothicm", aHGGothicM }, +{ "hgpgothicm", aHGPGothicM }, +{ "hgsgothicm", aHGSGothicM }, +{ "hggyoshotai", aHGGyoshotai }, +{ "hgpgyoshotai", aHGPGyoshotai }, +{ "hgsgyoshotai", aHGSGyoshotai }, +{ "hgkyokashotai", aHGKyokashotai }, +{ "hgpkyokashotai", aHGPKyokashotai }, +{ "hgskyokashotai", aHGSKyokashotai }, +{ "hgminchob", aHGMinchoB }, +{ "hgpminchob", aHGPMinchoB }, +{ "hgsminchob", aHGSMinchoB }, +{ "hgminchoe", aHGMinchoE }, +{ "hgpminchoe", aHGPMinchoE }, +{ "hgsminchoe", aHGSMinchoE }, +{ "hgsoeikakupoptai", aHGSoeiKakupoptai }, +{ "hgpsoeikakupopta", aHGPSoeiKakupoptai }, +{ "hgssoeikakupopta", aHGSSoeiKakupoptai }, +{ "hgsoeipresenceeb", aHGSoeiPresenceEB }, +{ "hgpsoeipresenceeb", aHGPSoeiPresenceEB }, +{ "hgssoeipresenceeb", aHGSSoeiPresenceEB }, +{ "hgsoeikakugothicub", aHGSoeiKakugothicUB }, +{ "hgpsoeikakugothicub", aHGPSoeiKakugothicUB }, +{ "hgssoeikakugothicub", aHGSSoeiKakugothicUB }, +{ "hgseikaishotaipro", aHGSeikaishotaiPRO }, +{ "hgmarugothicmpro", aHGMaruGothicMPRO }, +{ "hiraginominchopro", aHiraginoMinchoPro }, +{ "hiraginominchopron", aHiraginoMinchoProN }, +{ "hiraginosans", aHiraginoKakuGothic }, +{ "hiraginokakugothicpro", aHiraginoKakuGothicPro }, +{ "hiraginokakugothicpron", aHiraginoKakuGothicProN }, +{ "hiraginomarugothicpro", aHiraginoMaruGothicPro }, +{ "hiraginomarugothicpron", aHiraginoMaruGothicProN }, +{ nullptr, nullptr }, +}; + +OUString StripScriptFromName(const OUString& _aName) +{ + // I worry that someone will have a font which *does* have + // e.g. "Greek" legitimately at the end of its name :-( + const char*const suffixes[] = { " baltic", + " ce", + " cyr", + " greek", + " tur", + " (arabic)", + " (hebrew)", + " (thai)", + " (vietnamese)" + }; + + OUString aName = _aName; + // These can be crazily piled up, e.g. Times New Roman CYR Greek + bool bFinished = false; + while (!bFinished) + { + bFinished = true; + for (const char* suffix : suffixes) + { + size_t nLen = strlen(suffix); + if (aName.endsWithIgnoreAsciiCaseAsciiL(suffix, nLen)) + { + bFinished = false; + aName = aName.copy(0, aName.getLength() - nLen); + } + } + } + return aName; +} + +OUString GetEnglishSearchFontName(const OUString& rInName) +{ + OUStringBuffer rName(rInName); + bool bNeedTranslation = false; + sal_Int32 nLen = rName.getLength(); + + // Remove trailing whitespaces + sal_Int32 i = nLen; + while ( i && (rName[ i-1 ] < 32) ) + i--; + if ( i != nLen ) + rName.truncate(i); + + nLen = rName.getLength(); + + // remove all whitespaces and converts to lower case ASCII + // TODO: better transliteration to ASCII e.g. all digits + i = 0; + while ( i < nLen ) + { + sal_Unicode c = rName[ i ]; + if ( c > 127 ) + { + // Translate to Lowercase-ASCII + // FullWidth-ASCII to half ASCII + if ( (c >= 0xFF00) && (c <= 0xFF5E) ) + { + c -= 0xFF00-0x0020; + // Upper to Lower + if ( (c >= 'A') && (c <= 'Z') ) + c += 'a' - 'A'; + + rName[ i ] = c; + + } + else + { + // Only Fontnames with None-Ascii-Characters must be translated + bNeedTranslation = true; + } + } + // not lowercase Ascii + else if ( !((c >= 'a') && (c <= 'z')) ) + { + // To Lowercase-Ascii + if ( (c >= 'A') && (c <= 'Z') ) + { + c += 'a' - 'A'; + rName[ i ] = c; + } + else if( ((c < '0') || (c > '9')) && (c != ';') && (c != '(') && (c != ')') ) // not 0-9, semicolon, or brackets + { + // Remove white spaces and special characters + rName.remove(i,1); + nLen--; + continue; + } + } + + i++; + } + OUString rNameStr = rName.makeStringAndClear(); + // translate normalized localized name to its normalized English ASCII name + if( bNeedTranslation ) + { + typedef std::unordered_map<OUString, const char*> FontNameDictionary; + static FontNameDictionary aDictionary( SAL_N_ELEMENTS(aImplLocalizedNamesList) ); + // the font name dictionary needs to be initialized once + if( aDictionary.empty() ) + { + // TODO: check if all dictionary entries are already normalized? + const ImplLocalizedFontName* pList = aImplLocalizedNamesList; + for(; pList->mpEnglishName; ++pList ) + aDictionary[ pList->mpLocalizedNames ] = pList->mpEnglishName; + } + + FontNameDictionary::const_iterator it = aDictionary.find( rNameStr ); + if( it != aDictionary.end() ) + rNameStr = OUString::createFromAscii ( it->second ); + } + + return rNameStr; +} + +OUString GetNextFontToken( const OUString& rTokenStr, sal_Int32& rIndex ) +{ + // check for valid start index + sal_Int32 nStringLen = rTokenStr.getLength(); + if( rIndex >= nStringLen ) + { + rIndex = -1; + return OUString(); + } + + // find the next token delimiter and return the token substring + const sal_Unicode* pStr = rTokenStr.getStr() + rIndex; + const sal_Unicode* pEnd = rTokenStr.getStr() + nStringLen; + for(; pStr < pEnd; ++pStr ) + if( (*pStr == ';') || (*pStr == ',') ) + break; + + sal_Int32 nTokenStart = rIndex; + sal_Int32 nTokenLen; + if( pStr < pEnd ) + { + rIndex = sal::static_int_cast<sal_Int32>(pStr - rTokenStr.getStr()); + nTokenLen = rIndex - nTokenStart; + ++rIndex; // skip over token separator + } + else + { + // no token delimiter found => handle last token + rIndex = -1; + + // optimize if the token string consists of just one token + if( !nTokenStart ) + { + return rTokenStr; + } + else + { + nTokenLen = nStringLen - nTokenStart; + } + } + + return rTokenStr.copy( nTokenStart, nTokenLen ); +} + +static bool ImplIsFontToken( const OUString& rName, const OUString& rToken ) +{ + OUString aTempName; + sal_Int32 nIndex = 0; + do + { + aTempName = GetNextFontToken( rName, nIndex ); + if ( rToken == aTempName ) + return true; + } + while ( nIndex != -1 ); + + return false; +} + +static void ImplAppendFontToken( OUString& rName, const OUString& rNewToken ) +{ + if ( !rName.isEmpty() ) + { + rName += ";"; + } + rName += rNewToken; +} + +void AddTokenFontName( OUString& rName, const OUString& rNewToken ) +{ + if ( !ImplIsFontToken( rName, rNewToken ) ) + ImplAppendFontToken( rName, rNewToken ); +} + +OUString GetSubsFontName( const OUString& rName, SubsFontFlags nFlags ) +{ + OUString aName; + + sal_Int32 nIndex = 0; + OUString aOrgName = GetEnglishSearchFontName( + GetNextFontToken( rName, nIndex ) ); + + // #93662# do not try to replace StarSymbol with MS only font + if( nFlags == (SubsFontFlags::MS|SubsFontFlags::ONLYONE) + && ( aOrgName == "starsymbol" + || aOrgName == "opensymbol" ) ) + return aName; + + const utl::FontNameAttr* pAttr = utl::FontSubstConfiguration::get().getSubstInfo( aOrgName ); + if ( pAttr && (nFlags & SubsFontFlags::MS) ) + { + for( const auto& rSubstitution : pAttr->MSSubstitutions ) + if( ! ImplIsFontToken( rName, rSubstitution ) ) + { + ImplAppendFontToken( aName, rSubstitution ); + if( nFlags & SubsFontFlags::ONLYONE ) + { + break; + } + } + } + + return aName; +} + +bool IsStarSymbol(const OUString &rFontName) +{ + sal_Int32 nIndex = 0; + OUString sFamilyNm(GetNextFontToken(rFontName, nIndex)); + return (sFamilyNm.equalsIgnoreAsciiCase("starsymbol") || + sFamilyNm.equalsIgnoreAsciiCase("opensymbol")); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/misc/mediadescriptor.cxx b/unotools/source/misc/mediadescriptor.cxx new file mode 100644 index 000000000..7f8f4e3c3 --- /dev/null +++ b/unotools/source/misc/mediadescriptor.cxx @@ -0,0 +1,766 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <comphelper/docpasswordhelper.hxx> +#include <sal/log.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/mediadescriptor.hxx> +#include <unotools/securityoptions.hxx> +#include <unotools/ucbhelper.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/stillreadwriteinteraction.hxx> + +#include <com/sun/star/ucb/ContentCreationException.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/uri/UriReferenceFactory.hpp> +#include <com/sun/star/uri/XUriReference.hpp> +#include <com/sun/star/ucb/PostCommandArgument2.hpp> +#include <officecfg/Office/Common.hxx> +#include <ucbhelper/content.hxx> +#include <ucbhelper/commandenvironment.hxx> +#include <ucbhelper/activedatasink.hxx> +#include <comphelper/processfactory.hxx> +#include <tools/urlobj.hxx> +#include <osl/diagnose.h> +#include <tools/diagnose_ex.h> + +namespace utl { + +namespace { + +OUString removeFragment(OUString const & uri) { + css::uno::Reference< css::uri::XUriReference > ref( + css::uri::UriReferenceFactory::create( + comphelper::getProcessComponentContext())-> + parse(uri)); + if (ref.is()) { + ref->clearFragment(); + return ref->getUriReference(); + } else { + SAL_WARN("unotools.misc", "cannot parse <" << uri << ">"); + return uri; + } +} + +} + +const OUString& MediaDescriptor::PROP_ABORTED() +{ + static const OUString sProp("Aborted"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_ASTEMPLATE() +{ + static const OUString sProp("AsTemplate"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_COMPONENTDATA() +{ + static const OUString sProp("ComponentData"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_DOCUMENTSERVICE() +{ + static const OUString sProp("DocumentService"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_ENCRYPTIONDATA() +{ + static const OUString sProp("EncryptionData"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_FILENAME() +{ + static const OUString sProp("FileName"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_FILTERNAME() +{ + static const OUString sProp("FilterName"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_FILTERPROVIDER() +{ + static const OUString aProp("FilterProvider"); + return aProp; +} + +const OUString& MediaDescriptor::PROP_FILTEROPTIONS() +{ + static const OUString sProp("FilterOptions"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_FRAME() +{ + static const OUString sProp("Frame"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_FRAMENAME() +{ + static const OUString sProp("FrameName"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_HIDDEN() +{ + static const OUString sProp("Hidden"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_INPUTSTREAM() +{ + static const OUString sProp("InputStream"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_INTERACTIONHANDLER() +{ + static const OUString sProp("InteractionHandler"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_AUTHENTICATIONHANDLER() +{ + static const OUString sProp("AuthenticationHandler"); + return sProp; +} + + const OUString& MediaDescriptor::PROP_JUMPMARK() +{ + static const OUString sProp("JumpMark"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_MACROEXECUTIONMODE() +{ + static const OUString sProp("MacroExecutionMode"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_MEDIATYPE() +{ + static const OUString sProp("MediaType"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_MINIMIZED() +{ + static const OUString sProp("Minimized"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_NOAUTOSAVE() +{ + static const OUString sProp("NoAutoSave"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_OPENNEWVIEW() +{ + static const OUString sProp("OpenNewView"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_OUTPUTSTREAM() +{ + static const OUString sProp("OutputStream"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_POSTDATA() +{ + static const OUString sProp("PostData"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_PREVIEW() +{ + static const OUString sProp("Preview"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_READONLY() +{ + static const OUString sProp("ReadOnly"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_REFERRER() +{ + static const OUString sProp("Referer"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_REPLACEABLE() +{ + static const OUString sProp("Replaceable"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_STATUSINDICATOR() +{ + static const OUString sProp("StatusIndicator"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_STREAM() +{ + static const OUString sProp("Stream"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_STREAMFOROUTPUT() +{ + static const OUString sProp("StreamForOutput"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_TEMPLATENAME() +{ + static const OUString sProp("TemplateName"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_TYPENAME() +{ + static const OUString sProp("TypeName"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_UCBCONTENT() +{ + static const OUString sProp("UCBContent"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_UPDATEDOCMODE() +{ + static const OUString sProp("UpdateDocMode"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_URL() +{ + static const OUString sProp("URL"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_VERSION() +{ + static const OUString sProp("Version"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_DOCUMENTTITLE() +{ + static const OUString sProp("DocumentTitle"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_MODEL() +{ + static const OUString sProp("Model"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_PASSWORD() +{ + static const OUString sProp("Password"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_TITLE() +{ + static const OUString sProp("Title"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_SALVAGEDFILE() +{ + static const OUString sProp("SalvagedFile"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_VIEWONLY() +{ + static const OUString sProp("ViewOnly"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_DOCUMENTBASEURL() +{ + static const OUString sProp("DocumentBaseURL"); + return sProp; +} + +const OUString& MediaDescriptor::PROP_SUGGESTEDSAVEASNAME() +{ + static const OUString sProp("SuggestedSaveAsName"); + return sProp; +} + +MediaDescriptor::MediaDescriptor() + : SequenceAsHashMap() +{ +} + +MediaDescriptor::MediaDescriptor(const css::uno::Sequence< css::beans::PropertyValue >& lSource) + : SequenceAsHashMap(lSource) +{ +} + +bool MediaDescriptor::isStreamReadOnly() const +{ + bool bReadOnly = false; + + // check for explicit readonly state + const_iterator pIt = find(MediaDescriptor::PROP_READONLY()); + if (pIt != end()) + { + pIt->second >>= bReadOnly; + return bReadOnly; + } + + // streams based on post data are readonly by definition + pIt = find(MediaDescriptor::PROP_POSTDATA()); + if (pIt != end()) + return true; + + // A XStream capsulate XInputStream and XOutputStream ... + // If it exists - the file must be open in read/write mode! + pIt = find(MediaDescriptor::PROP_STREAM()); + if (pIt != end()) + return false; + + // Only file system content provider is able to provide XStream + // so for this content impossibility to create XStream triggers + // switch to readonly mode. + try + { + css::uno::Reference< css::ucb::XContent > xContent = getUnpackedValueOrDefault(MediaDescriptor::PROP_UCBCONTENT(), css::uno::Reference< css::ucb::XContent >()); + if (xContent.is()) + { + css::uno::Reference< css::ucb::XContentIdentifier > xId = xContent->getIdentifier(); + OUString aScheme; + if (xId.is()) + aScheme = xId->getContentProviderScheme(); + + if (aScheme.equalsIgnoreAsciiCase("file")) + bReadOnly = true; + else + { + ::ucbhelper::Content aContent(xContent, + utl::UCBContentHelper::getDefaultCommandEnvironment(), + comphelper::getProcessComponentContext()); + aContent.getPropertyValue("IsReadOnly") >>= bReadOnly; + } + } + } + catch(const css::uno::RuntimeException& ) + { throw; } + catch(const css::uno::Exception&) + {} + + return bReadOnly; +} + +css::uno::Any MediaDescriptor::getComponentDataEntry( const OUString& rName ) const +{ + comphelper::SequenceAsHashMap::const_iterator aPropertyIter = find( PROP_COMPONENTDATA() ); + if( aPropertyIter != end() ) + return comphelper::NamedValueCollection( aPropertyIter->second ).get( rName ); + return css::uno::Any(); +} + +void MediaDescriptor::setComponentDataEntry( const OUString& rName, const css::uno::Any& rValue ) +{ + if( rValue.hasValue() ) + { + // get or create the 'ComponentData' property entry + css::uno::Any& rCompDataAny = operator[]( PROP_COMPONENTDATA() ); + // insert the value (retain sequence type, create NamedValue elements by default) + bool bHasNamedValues = !rCompDataAny.hasValue() || rCompDataAny.has< css::uno::Sequence< css::beans::NamedValue > >(); + bool bHasPropValues = rCompDataAny.has< css::uno::Sequence< css::beans::PropertyValue > >(); + OSL_ENSURE( bHasNamedValues || bHasPropValues, "MediaDescriptor::setComponentDataEntry - incompatible 'ComponentData' property in media descriptor" ); + if( bHasNamedValues || bHasPropValues ) + { + // insert or overwrite the passed value + comphelper::SequenceAsHashMap aCompDataMap( rCompDataAny ); + aCompDataMap[ rName ] = rValue; + // write back the sequence (restore sequence with correct element type) + rCompDataAny = aCompDataMap.getAsConstAny( bHasPropValues ); + } + } + else + { + // if an empty Any is passed, clear the entry + clearComponentDataEntry( rName ); + } +} + +void MediaDescriptor::clearComponentDataEntry( const OUString& rName ) +{ + comphelper::SequenceAsHashMap::iterator aPropertyIter = find( PROP_COMPONENTDATA() ); + if( aPropertyIter != end() ) + { + css::uno::Any& rCompDataAny = aPropertyIter->second; + bool bHasNamedValues = rCompDataAny.has< css::uno::Sequence< css::beans::NamedValue > >(); + bool bHasPropValues = rCompDataAny.has< css::uno::Sequence< css::beans::PropertyValue > >(); + OSL_ENSURE( bHasNamedValues || bHasPropValues, "MediaDescriptor::clearComponentDataEntry - incompatible 'ComponentData' property in media descriptor" ); + if( bHasNamedValues || bHasPropValues ) + { + // remove the value with the passed name + comphelper::SequenceAsHashMap aCompDataMap( rCompDataAny ); + aCompDataMap.erase( rName ); + // write back the sequence, or remove it completely if it is empty + if( aCompDataMap.empty() ) + erase( aPropertyIter ); + else + rCompDataAny = aCompDataMap.getAsConstAny( bHasPropValues ); + } + } +} + +css::uno::Sequence< css::beans::NamedValue > MediaDescriptor::requestAndVerifyDocPassword( + comphelper::IDocPasswordVerifier& rVerifier, + comphelper::DocPasswordRequestType eRequestType, + const ::std::vector< OUString >* pDefaultPasswords ) +{ + css::uno::Sequence< css::beans::NamedValue > aMediaEncData = getUnpackedValueOrDefault( + PROP_ENCRYPTIONDATA(), css::uno::Sequence< css::beans::NamedValue >() ); + OUString aMediaPassword = getUnpackedValueOrDefault( + PROP_PASSWORD(), OUString() ); + css::uno::Reference< css::task::XInteractionHandler > xInteractHandler = getUnpackedValueOrDefault( + PROP_INTERACTIONHANDLER(), css::uno::Reference< css::task::XInteractionHandler >() ); + OUString aDocumentName = getUnpackedValueOrDefault( + PROP_URL(), OUString() ); + + bool bIsDefaultPassword = false; + css::uno::Sequence< css::beans::NamedValue > aEncryptionData = comphelper::DocPasswordHelper::requestAndVerifyDocPassword( + rVerifier, aMediaEncData, aMediaPassword, xInteractHandler, aDocumentName, eRequestType, pDefaultPasswords, &bIsDefaultPassword ); + + erase( PROP_PASSWORD() ); + erase( PROP_ENCRYPTIONDATA() ); + + // insert encryption info into media descriptor + // TODO + if( aEncryptionData.hasElements() ) + (*this)[ PROP_ENCRYPTIONDATA() ] <<= aEncryptionData; + + return aEncryptionData; +} + +bool MediaDescriptor::addInputStream() +{ + return impl_addInputStream( true ); +} + +/*-----------------------------------------------*/ +bool MediaDescriptor::addInputStreamOwnLock() +{ + const bool bLock = !utl::ConfigManager::IsFuzzing() + && officecfg::Office::Common::Misc::UseDocumentSystemFileLocking::get(); + return impl_addInputStream(bLock); +} + +/*-----------------------------------------------*/ +bool MediaDescriptor::impl_addInputStream( bool bLockFile ) +{ + // check for an already existing stream item first + const_iterator pIt = find(MediaDescriptor::PROP_INPUTSTREAM()); + if (pIt != end()) + return true; + + try + { + // No stream available - create a new one + // a) data comes as PostData ... + pIt = find(MediaDescriptor::PROP_POSTDATA()); + if (pIt != end()) + { + const css::uno::Any& rPostData = pIt->second; + css::uno::Reference< css::io::XInputStream > xPostData; + rPostData >>= xPostData; + + return impl_openStreamWithPostData( xPostData ); + } + + // b) ... or we must get it from the given URL + OUString sURL = getUnpackedValueOrDefault(MediaDescriptor::PROP_URL(), OUString()); + if (sURL.isEmpty()) + throw css::uno::Exception("Found no URL.", + css::uno::Reference< css::uno::XInterface >()); + + return impl_openStreamWithURL( removeFragment(sURL), bLockFile ); + } + catch(const css::uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("unotools.misc", "invalid MediaDescriptor detected"); + return false; + } +} + +bool MediaDescriptor::impl_openStreamWithPostData( const css::uno::Reference< css::io::XInputStream >& _rxPostData ) +{ + if ( !_rxPostData.is() ) + throw css::lang::IllegalArgumentException("Found invalid PostData.", + css::uno::Reference< css::uno::XInterface >(), 1); + + // PostData can't be used in read/write mode! + (*this)[MediaDescriptor::PROP_READONLY()] <<= true; + + // prepare the environment + css::uno::Reference< css::task::XInteractionHandler > xInteraction = getUnpackedValueOrDefault( + MediaDescriptor::PROP_INTERACTIONHANDLER(), + css::uno::Reference< css::task::XInteractionHandler >()); + css::uno::Reference< css::ucb::XProgressHandler > xProgress; + ::ucbhelper::CommandEnvironment* pCommandEnv = new ::ucbhelper::CommandEnvironment(xInteraction, xProgress); + css::uno::Reference< css::ucb::XCommandEnvironment > xCommandEnv(static_cast< css::ucb::XCommandEnvironment* >(pCommandEnv), css::uno::UNO_QUERY); + + // media type + OUString sMediaType = getUnpackedValueOrDefault(MediaDescriptor::PROP_MEDIATYPE(), OUString()); + if (sMediaType.isEmpty()) + { + sMediaType = "application/x-www-form-urlencoded"; + (*this)[MediaDescriptor::PROP_MEDIATYPE()] <<= sMediaType; + } + + // url + OUString sURL( getUnpackedValueOrDefault( PROP_URL(), OUString() ) ); + + css::uno::Reference< css::io::XInputStream > xResultStream; + try + { + // seek PostData stream to the beginning + css::uno::Reference< css::io::XSeekable > xSeek( _rxPostData, css::uno::UNO_QUERY ); + if ( xSeek.is() ) + xSeek->seek( 0 ); + + // a content for the URL + ::ucbhelper::Content aContent( sURL, xCommandEnv, comphelper::getProcessComponentContext() ); + + // use post command + css::ucb::PostCommandArgument2 aPostArgument; + aPostArgument.Source = _rxPostData; + css::uno::Reference< css::io::XActiveDataSink > xSink( new ucbhelper::ActiveDataSink ); + aPostArgument.Sink = xSink; + aPostArgument.MediaType = sMediaType; + aPostArgument.Referer = getUnpackedValueOrDefault( PROP_REFERRER(), OUString() ); + + aContent.executeCommand( "post", css::uno::makeAny( aPostArgument ) ); + + // get result + xResultStream = xSink->getInputStream(); + } + catch( const css::uno::Exception& ) + { + } + + // success? + if ( !xResultStream.is() ) + { + OSL_FAIL( "no valid reply to the HTTP-Post" ); + return false; + } + + (*this)[MediaDescriptor::PROP_INPUTSTREAM()] <<= xResultStream; + return true; +} + +/*-----------------------------------------------*/ +bool MediaDescriptor::impl_openStreamWithURL( const OUString& sURL, bool bLockFile ) +{ + OUString referer(getUnpackedValueOrDefault(PROP_REFERRER(), OUString())); + if (SvtSecurityOptions().isUntrustedReferer(referer)) { + return false; + } + + // prepare the environment + css::uno::Reference< css::task::XInteractionHandler > xOrgInteraction = getUnpackedValueOrDefault( + MediaDescriptor::PROP_INTERACTIONHANDLER(), + css::uno::Reference< css::task::XInteractionHandler >()); + + css::uno::Reference< css::task::XInteractionHandler > xAuthenticationInteraction = getUnpackedValueOrDefault( + MediaDescriptor::PROP_AUTHENTICATIONHANDLER(), + css::uno::Reference< css::task::XInteractionHandler >()); + + comphelper::StillReadWriteInteraction* pInteraction = new comphelper::StillReadWriteInteraction(xOrgInteraction,xAuthenticationInteraction); + css::uno::Reference< css::task::XInteractionHandler > xInteraction(static_cast< css::task::XInteractionHandler* >(pInteraction), css::uno::UNO_QUERY); + + css::uno::Reference< css::ucb::XProgressHandler > xProgress; + ::ucbhelper::CommandEnvironment* pCommandEnv = new ::ucbhelper::CommandEnvironment(xInteraction, xProgress); + css::uno::Reference< css::ucb::XCommandEnvironment > xCommandEnv(static_cast< css::ucb::XCommandEnvironment* >(pCommandEnv), css::uno::UNO_QUERY); + + // try to create the content + // no content -> no stream => return immediately with FALSE + ::ucbhelper::Content aContent; + css::uno::Reference< css::ucb::XContent > xContent; + try + { + aContent = ::ucbhelper::Content(sURL, xCommandEnv, comphelper::getProcessComponentContext()); + xContent = aContent.get(); + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::ucb::ContentCreationException&) + { + TOOLS_WARN_EXCEPTION("unotools.misc", "url: '" << sURL << "'"); + return false; // TODO error handling + } + catch(const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("unotools.misc", "url: '" << sURL << "'"); + return false; // TODO error handling + } + + // try to open the file in read/write mode + // (if it's allowed to do so). + // But handle errors in a "hidden mode". Because + // we try it readonly later - if read/write is not an option. + css::uno::Reference< css::io::XStream > xStream; + css::uno::Reference< css::io::XInputStream > xInputStream; + + bool bReadOnly = false; + bool bModeRequestedExplicitly = false; + const_iterator pIt = find(MediaDescriptor::PROP_READONLY()); + if (pIt != end()) + { + pIt->second >>= bReadOnly; + bModeRequestedExplicitly = true; + } + + if ( !bReadOnly && bLockFile ) + { + try + { + // TODO: use "special" still interaction to suppress error messages + xStream = aContent.openWriteableStream(); + if (xStream.is()) + xInputStream = xStream->getInputStream(); + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception&) + { + css::uno::Any ex( cppu::getCaughtException() ); + // ignore exception, if reason was problem reasoned on + // open it in WRITABLE mode! Then we try it READONLY + // later a second time. + // All other errors must be handled as real error an + // break this method. + if (!pInteraction->wasWriteError() || bModeRequestedExplicitly) + { + SAL_WARN("unotools.misc","url: '" << sURL << "' " << exceptionToString(ex)); + // If the protocol is webdav, then we need to treat the stream as readonly, even if the + // operation was requested as read/write explicitly (the WebDAV UCB implementation is monodirectional + // read or write not both at the same time). + if ( !INetURLObject( sURL ).isAnyKnownWebDAVScheme() ) + return false; + } + xStream.clear(); + xInputStream.clear(); + } + } + + // If opening of the stream in read/write mode was not allowed + // or failed by an error - we must try it in readonly mode. + if (!xInputStream.is()) + { + OUString aScheme; + + try + { + css::uno::Reference< css::ucb::XContentIdentifier > xContId( + aContent.get().is() ? aContent.get()->getIdentifier() : nullptr ); + + if ( xContId.is() ) + aScheme = xContId->getContentProviderScheme(); + + // Only file system content provider is able to provide XStream + // so for this content impossibility to create XStream triggers + // switch to readonly mode in case of opening with locking on + if( bLockFile && aScheme.equalsIgnoreAsciiCase("file") ) + bReadOnly = true; + else + { + bool bRequestReadOnly = bReadOnly; + aContent.getPropertyValue("IsReadOnly") >>= bReadOnly; + if ( bReadOnly && !bRequestReadOnly && bModeRequestedExplicitly ) + return false; // the document is explicitly requested with WRITABLE mode + } + } + catch(const css::uno::RuntimeException&) + { throw; } + catch(const css::uno::Exception&) + { /* no error handling if IsReadOnly property does not exist for UCP */ } + + if ( bReadOnly ) + (*this)[MediaDescriptor::PROP_READONLY()] <<= bReadOnly; + + pInteraction->resetInterceptions(); + pInteraction->resetErrorStates(); + try + { + // all the contents except file-URLs should be opened as usual + if ( bLockFile || !aScheme.equalsIgnoreAsciiCase("file") ) + xInputStream = aContent.openStream(); + else + xInputStream = aContent.openStreamNoLock(); + } + catch(const css::uno::RuntimeException&) + { + throw; + } + catch(const css::uno::Exception&) + { + TOOLS_INFO_EXCEPTION("unotools.misc","url: '" << sURL << "'"); + return false; + } + } + + // add streams to the descriptor + if (xContent.is()) + (*this)[MediaDescriptor::PROP_UCBCONTENT()] <<= xContent; + if (xStream.is()) + (*this)[MediaDescriptor::PROP_STREAM()] <<= xStream; + if (xInputStream.is()) + (*this)[MediaDescriptor::PROP_INPUTSTREAM()] <<= xInputStream; + + // At least we need an input stream. The r/w stream is optional ... + return xInputStream.is(); +} + +} // namespace comphelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/misc/sharedunocomponent.cxx b/unotools/source/misc/sharedunocomponent.cxx new file mode 100644 index 000000000..789054104 --- /dev/null +++ b/unotools/source/misc/sharedunocomponent.cxx @@ -0,0 +1,199 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> +#include <osl/diagnose.h> + +#include <unotools/sharedunocomponent.hxx> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/util/CloseVetoException.hpp> +#include <com/sun/star/util/XCloseable.hpp> +#include <cppuhelper/implbase.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> + +namespace utl +{ + + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::util::XCloseable; + using ::com::sun::star::util::XCloseListener; + using ::com::sun::star::util::CloseVetoException; + + //= DisposableComponent + + DisposableComponent::DisposableComponent( const Reference< XInterface >& _rxComponent ) + :m_xComponent( _rxComponent, UNO_QUERY ) + { + DBG_ASSERT( m_xComponent.is() || !_rxComponent.is(), "DisposableComponent::DisposableComponent: should be an XComponent!" ); + } + + DisposableComponent::~DisposableComponent() + { + if ( m_xComponent.is() ) + { + try + { + m_xComponent->dispose(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "unotools", "DisposableComponent::~DisposableComponent" ); + } + m_xComponent.clear(); + } + } + + typedef ::cppu::WeakImplHelper < XCloseListener + > CloseableComponentImpl_Base; + class CloseableComponentImpl : public CloseableComponentImpl_Base + { + private: + Reference< XCloseable > m_xCloseable; + + CloseableComponentImpl(const CloseableComponentImpl&) = delete; + CloseableComponentImpl& operator=(const CloseableComponentImpl&) = delete; + + public: + explicit CloseableComponentImpl( const Reference< XInterface >& _rxComponent ); + + /** closes the component + + @nofail + */ + void nf_closeComponent(); + + protected: + virtual ~CloseableComponentImpl() override; + + // XCloseListener overridables + virtual void SAL_CALL queryClosing( const EventObject& Source, sal_Bool GetsOwnership ) override; + virtual void SAL_CALL notifyClosing( const EventObject& Source ) override; + + // XEventListener overridables + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + private: + /** starts or stops being a CloseListener at the component + + Only to be called upon construction of the instance, or when the component + is to be closed. + + @nofail + */ + void impl_nf_switchListening( bool _bListen ); + }; + + CloseableComponentImpl::CloseableComponentImpl( const Reference< XInterface >& _rxComponent ) + :m_xCloseable( _rxComponent, UNO_QUERY ) + { + DBG_ASSERT( m_xCloseable.is() || !_rxComponent.is(), "CloseableComponentImpl::CloseableComponentImpl: component is not an XCloseable!" ); + impl_nf_switchListening( true ); + } + + CloseableComponentImpl::~CloseableComponentImpl() + { + nf_closeComponent(); + } + + void CloseableComponentImpl::nf_closeComponent() + { + if ( !m_xCloseable.is() ) + // nothing to do + return; + + // stop listening + impl_nf_switchListening( false ); + + // close + try + { + m_xCloseable->close( true ); + } + catch( const CloseVetoException& ) { /* fine */ } + catch( const Exception& ) + { + OSL_FAIL( "CloseableComponentImpl::nf_closeComponent: caught an unexpected exception!" ); + } + + // reset + m_xCloseable.clear(); + } + + void CloseableComponentImpl::impl_nf_switchListening( bool _bListen ) + { + if ( !m_xCloseable.is() ) + return; + + try + { + if ( _bListen ) + m_xCloseable->addCloseListener( this ); + else + m_xCloseable->removeCloseListener( this ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "unotools", "CloseableComponentImpl::impl_nf_switchListening" ); + } + } + + void SAL_CALL CloseableComponentImpl::queryClosing( const EventObject& Source, sal_Bool /*GetsOwnership*/ ) + { + // as long as we live, somebody wants to keep the object alive. So, veto the + // closing + DBG_ASSERT( Source.Source == m_xCloseable, "CloseableComponentImpl::queryClosing: where did this come from?" ); + throw CloseVetoException(); + } + + void SAL_CALL CloseableComponentImpl::notifyClosing( const EventObject& Source ) + { + DBG_ASSERT( Source.Source == m_xCloseable, "CloseableComponentImpl::notifyClosing: where did this come from?" ); + + // this should be unreachable: As long as we're a CloseListener, we veto the closing. If we're going + // to close the component ourself, then we revoke ourself as listener *before* the close call. So, + // if this here fires, something went definitely wrong. + OSL_FAIL( "CloseableComponentImpl::notifyClosing: unreachable!" ); + } + + void SAL_CALL CloseableComponentImpl::disposing( const EventObject& Source ) + { + DBG_ASSERT( Source.Source == m_xCloseable, "CloseableComponentImpl::disposing: where did this come from?" ); + OSL_FAIL( "CloseableComponentImpl::disposing: unreachable!" ); + // same reasoning for this assertion as in ->notifyClosing + } + + CloseableComponent::CloseableComponent( const Reference< XInterface >& _rxComponent ) + :m_pImpl( new CloseableComponentImpl( _rxComponent ) ) + { + } + + CloseableComponent::~CloseableComponent() + { + // close the component, deliver ownership to anybody who wants to veto the close + m_pImpl->nf_closeComponent(); + } + +} // namespace utl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/misc/syslocale.cxx b/unotools/source/misc/syslocale.cxx new file mode 100644 index 000000000..7f89d34f3 --- /dev/null +++ b/unotools/source/misc/syslocale.cxx @@ -0,0 +1,222 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <sal/log.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/charclass.hxx> +#include <unotools/syslocale.hxx> +#include <unotools/syslocaleoptions.hxx> +#include <comphelper/lok.hxx> +#include <comphelper/sequence.hxx> +#include <rtl/tencinfo.h> +#include <rtl/locale.h> +#include <osl/thread.h> +#include <osl/nlsupport.h> + +#include <vector> +#include <memory> + +using namespace osl; +using namespace com::sun::star; + +namespace { + +std::weak_ptr<SvtSysLocale_Impl> g_pSysLocale; + +} + +class SvtSysLocale_Impl : public utl::ConfigurationListener +{ +public: + SvtSysLocaleOptions aSysLocaleOptions; + std::unique_ptr<LocaleDataWrapper> pLocaleData; + std::unique_ptr<CharClass> pCharClass; + + SvtSysLocale_Impl(); + virtual ~SvtSysLocale_Impl() override; + + CharClass* GetCharClass(); + virtual void ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints ) override; + +private: + void setDateAcceptancePatternsConfig(); +}; + +SvtSysLocale_Impl::SvtSysLocale_Impl() +{ + pLocaleData.reset(new LocaleDataWrapper( aSysLocaleOptions.GetRealLanguageTag() )); + setDateAcceptancePatternsConfig(); + + // listen for further changes + aSysLocaleOptions.AddListener( this ); +} + +SvtSysLocale_Impl::~SvtSysLocale_Impl() +{ + aSysLocaleOptions.RemoveListener( this ); +} + +CharClass* SvtSysLocale_Impl::GetCharClass() +{ + if ( !pCharClass ) + pCharClass.reset(new CharClass( aSysLocaleOptions.GetRealLanguageTag() )); + return pCharClass.get(); +} + +void SvtSysLocale_Impl::ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints nHint ) +{ + MutexGuard aGuard( SvtSysLocale::GetMutex() ); + + if ( nHint & ConfigurationHints::Locale ) + { + const LanguageTag& rLanguageTag = aSysLocaleOptions.GetRealLanguageTag(); + pLocaleData->setLanguageTag( rLanguageTag ); + GetCharClass()->setLanguageTag( rLanguageTag ); + } + if ( nHint & ConfigurationHints::DatePatterns ) + { + setDateAcceptancePatternsConfig(); + } +} + +void SvtSysLocale_Impl::setDateAcceptancePatternsConfig() +{ + OUString aStr( aSysLocaleOptions.GetDatePatternsConfigString()); + if (aStr.isEmpty()) + pLocaleData->setDateAcceptancePatterns( uno::Sequence<OUString>()); // reset + else + { + ::std::vector< OUString > aVec; + for (sal_Int32 nIndex = 0; nIndex >= 0; /*nop*/) + { + OUString aTok( aStr.getToken( 0, ';', nIndex)); + if (!aTok.isEmpty()) + aVec.push_back( aTok); + } + pLocaleData->setDateAcceptancePatterns( comphelper::containerToSequence(aVec) ); + } +} + +SvtSysLocale::SvtSysLocale() +{ + MutexGuard aGuard( GetMutex() ); + pImpl = g_pSysLocale.lock(); + if ( !pImpl ) + { + pImpl = std::make_shared<SvtSysLocale_Impl>(); + g_pSysLocale = pImpl; + } +} + +SvtSysLocale::~SvtSysLocale() +{ + MutexGuard aGuard( GetMutex() ); + pImpl.reset(); +} + +// static +Mutex& SvtSysLocale::GetMutex() +{ + // #i77768# Due to a static reference in the toolkit lib + // we need a mutex that lives longer than the svl library. + // Otherwise the dtor would use a destructed mutex!! + static Mutex* persistentMutex(new Mutex); + + return *persistentMutex; +} + +const LocaleDataWrapper& SvtSysLocale::GetLocaleData() const +{ + return *(pImpl->pLocaleData); +} + +const LocaleDataWrapper* SvtSysLocale::GetLocaleDataPtr() const +{ + return pImpl->pLocaleData.get(); +} + +const CharClass& SvtSysLocale::GetCharClass() const +{ + return *(pImpl->GetCharClass()); +} + +const CharClass* SvtSysLocale::GetCharClassPtr() const +{ + return pImpl->GetCharClass(); +} + +SvtSysLocaleOptions& SvtSysLocale::GetOptions() const +{ + return pImpl->aSysLocaleOptions; +} + +const LanguageTag& SvtSysLocale::GetLanguageTag() const +{ + if (comphelper::LibreOfficeKit::isActive()) + return comphelper::LibreOfficeKit::getLocale(); + + return pImpl->aSysLocaleOptions.GetRealLanguageTag(); +} + +const LanguageTag& SvtSysLocale::GetUILanguageTag() const +{ + if (comphelper::LibreOfficeKit::isActive()) + return comphelper::LibreOfficeKit::getLanguageTag(); + + return pImpl->aSysLocaleOptions.GetRealUILanguageTag(); +} + +// static +rtl_TextEncoding SvtSysLocale::GetBestMimeEncoding() +{ + const char* pCharSet = rtl_getBestMimeCharsetFromTextEncoding( + osl_getThreadTextEncoding() ); + if ( !pCharSet ) + { + // If the system locale is unknown to us, e.g. LC_ALL=xx, match the UI + // language if possible. + SvtSysLocale aSysLocale; + const LanguageTag& rLanguageTag = aSysLocale.GetUILanguageTag(); + // Converting blindly to Locale and then to rtl_Locale may feed the + // 'qlt' to rtl_locale_register() and the underlying system locale + // stuff, which doesn't know about it nor about BCP47 in the Variant + // field. So use the real language and for non-pure ISO cases hope for + // the best... the fallback to UTF-8 should solve these cases nowadays. + /* FIXME-BCP47: the script needs to go in here as well, so actually + * we'd need some variant fiddling or glibc locale string and tweak + * rtl_locale_register() to know about it! But then again the Windows + * implementation still wouldn't know anything about it ... */ + SAL_WARN_IF( !rLanguageTag.isIsoLocale(), "unotools.i18n", + "SvtSysLocale::GetBestMimeEncoding - non-ISO UI locale"); + rtl_Locale * pLocale = rtl_locale_register( rLanguageTag.getLanguage().getStr(), + rLanguageTag.getCountry().getStr(), OUString().getStr() ); + rtl_TextEncoding nEnc = osl_getTextEncodingFromLocale( pLocale ); + pCharSet = rtl_getBestMimeCharsetFromTextEncoding( nEnc ); + } + rtl_TextEncoding nRet; + if ( pCharSet ) + nRet = rtl_getTextEncodingFromMimeCharset( pCharSet ); + else + nRet = RTL_TEXTENCODING_UTF8; + return nRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/misc/unotoolsservices.cxx b/unotools/source/misc/unotoolsservices.cxx new file mode 100644 index 000000000..4d1d897f1 --- /dev/null +++ b/unotools/source/misc/unotoolsservices.cxx @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <comphelper/servicedecl.hxx> + +#include <unotoolsservices.hxx> + +namespace sdecl = ::comphelper::service_decl; + +extern "C" SAL_DLLPUBLIC_EXPORT void* utl_component_getFactory( + char const* pImplName, void*, void*) +{ + return sdecl::component_getFactoryHelper( pImplName, + {&OTempFileServiceDecl, &ServiceDocumenterDecl}); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unotools/source/misc/wincodepage.cxx b/unotools/source/misc/wincodepage.cxx new file mode 100644 index 000000000..1fefabecb --- /dev/null +++ b/unotools/source/misc/wincodepage.cxx @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <unotools/wincodepage.hxx> +#include <rtl/string.h> +#include <rtl/textenc.h> + +namespace{ + +struct LangEncodingDef +{ + const OUStringLiteral msLangStr; + rtl_TextEncoding meTextEncoding; +}; + +// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756 +rtl_TextEncoding impl_getWinTextEncodingFromLangStrANSI(const OUString& sLanguage) +{ + static constexpr LangEncodingDef aLanguageTab[] = + { + { "en", RTL_TEXTENCODING_MS_1252 }, // Most used -> first in list + { "th", RTL_TEXTENCODING_MS_874 }, + { "ja", RTL_TEXTENCODING_MS_932 }, + { "zh-cn", RTL_TEXTENCODING_MS_936 }, // Chinese (simplified) - must go before "zh" + { "ko", RTL_TEXTENCODING_MS_949 }, + { "zh", RTL_TEXTENCODING_MS_950 }, // Chinese (traditional) + { "bs", RTL_TEXTENCODING_MS_1250 }, + { "cs", RTL_TEXTENCODING_MS_1250 }, + { "hr", RTL_TEXTENCODING_MS_1250 }, + { "hu", RTL_TEXTENCODING_MS_1250 }, + { "pl", RTL_TEXTENCODING_MS_1250 }, + { "ro", RTL_TEXTENCODING_MS_1250 }, + { "sk", RTL_TEXTENCODING_MS_1250 }, + { "sl", RTL_TEXTENCODING_MS_1250 }, +// { "sr", RTL_TEXTENCODING_MS_1250 }, + { "sq", RTL_TEXTENCODING_MS_1250 }, + { "be", RTL_TEXTENCODING_MS_1251 }, + { "bg", RTL_TEXTENCODING_MS_1251 }, + { "mk", RTL_TEXTENCODING_MS_1251 }, + { "ru", RTL_TEXTENCODING_MS_1251 }, + { "sr", RTL_TEXTENCODING_MS_1251 }, + { "uk", RTL_TEXTENCODING_MS_1251 }, + { "es", RTL_TEXTENCODING_MS_1252 }, + { "el", RTL_TEXTENCODING_MS_1253 }, + { "tr", RTL_TEXTENCODING_MS_1254 }, + { "he", RTL_TEXTENCODING_MS_1255 }, + { "ar", RTL_TEXTENCODING_MS_1256 }, + { "et", RTL_TEXTENCODING_MS_1257 }, + { "lt", RTL_TEXTENCODING_MS_1257 }, + { "lv", RTL_TEXTENCODING_MS_1257 }, + { "vi", RTL_TEXTENCODING_MS_1258 }, + }; + + for (auto& def : aLanguageTab) + { + if (sLanguage.startsWithIgnoreAsciiCase(def.msLangStr)) + return def.meTextEncoding; + } + + return RTL_TEXTENCODING_MS_1252; +} + +/* ----------------------------------------------------------------------- */ + +// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756 +// See http://shapelib.maptools.org/codepage.html +rtl_TextEncoding impl_getWinTextEncodingFromLangStrOEM(const OUString& sLanguage) +{ + static constexpr LangEncodingDef aLanguageTab[] = + { + { "de", RTL_TEXTENCODING_IBM_437 }, // OEM United States + { "en-us", RTL_TEXTENCODING_IBM_437 }, // OEM United States + { "fi", RTL_TEXTENCODING_IBM_437 }, // OEM United States + { "fr-ca", RTL_TEXTENCODING_IBM_863 }, // OEM French Canadian; French Canadian (DOS) + { "fr", RTL_TEXTENCODING_IBM_437 }, // OEM United States + { "it", RTL_TEXTENCODING_IBM_437 }, // OEM United States + { "nl", RTL_TEXTENCODING_IBM_437 }, // OEM United States + { "sv", RTL_TEXTENCODING_IBM_437 }, // OEM United States + { "el", RTL_TEXTENCODING_IBM_737 }, // OEM Greek (formerly 437G); Greek (DOS) + { "et", RTL_TEXTENCODING_IBM_775 }, // OEM Baltic; Baltic (DOS) + { "lt", RTL_TEXTENCODING_IBM_775 }, // OEM Baltic; Baltic (DOS) + { "lv", RTL_TEXTENCODING_IBM_775 }, // OEM Baltic; Baltic (DOS) + { "en", RTL_TEXTENCODING_IBM_850 }, // OEM Multilingual Latin 1; Western European (DOS) + { "bs", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS) + { "cs", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS) + { "hr", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS) + { "hu", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS) + { "pl", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS) + { "ro", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS) + { "sk", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS) + { "sl", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS) +// { "sr", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS) + { "bg", RTL_TEXTENCODING_IBM_855 }, // OEM Cyrillic (primarily Russian) + { "mk", RTL_TEXTENCODING_IBM_855 }, // OEM Cyrillic (primarily Russian) + { "sr", RTL_TEXTENCODING_IBM_855 }, // OEM Cyrillic (primarily Russian) + { "tr", RTL_TEXTENCODING_IBM_857 }, // OEM Turkish; Turkish (DOS) + { "pt", RTL_TEXTENCODING_IBM_860 }, // OEM Portuguese; Portuguese (DOS) + { "is", RTL_TEXTENCODING_IBM_861 }, // OEM Icelandic; Icelandic (DOS) + { "he", RTL_TEXTENCODING_IBM_862 }, // OEM Hebrew; Hebrew (DOS) + { "ar", RTL_TEXTENCODING_IBM_864 }, // OEM Arabic; Arabic (864) + { "da", RTL_TEXTENCODING_IBM_865 }, // OEM Nordic; Nordic (DOS) + { "nn", RTL_TEXTENCODING_IBM_865 }, // OEM Nordic; Nordic (DOS) + { "be", RTL_TEXTENCODING_IBM_866 }, // OEM Russian; Cyrillic (DOS) + { "ru", RTL_TEXTENCODING_IBM_866 }, // OEM Russian; Cyrillic (DOS) + { "uk", RTL_TEXTENCODING_IBM_866 }, // OEM Russian; Cyrillic (DOS) + { "th", RTL_TEXTENCODING_MS_874 }, // ANSI/OEM Thai (ISO 8859-11); Thai (Windows) + { "ja", RTL_TEXTENCODING_MS_932 }, // ANSI/OEM Japanese; Japanese (Shift-JIS) + { "zh-cn", RTL_TEXTENCODING_MS_936 }, // ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) + { "ko", RTL_TEXTENCODING_MS_949 }, // ANSI/OEM Korean (Unified Hangul Code) + { "zh", RTL_TEXTENCODING_MS_950 }, // ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) + { "vi", RTL_TEXTENCODING_MS_1258 }, // ANSI/OEM Vietnamese; Vietnamese (Windows) + }; + + for (auto& def : aLanguageTab) + { + if (sLanguage.startsWithIgnoreAsciiCase(def.msLangStr)) + return def.meTextEncoding; + } + + return RTL_TEXTENCODING_IBM_850; +} + +} // namespace + +rtl_TextEncoding utl_getWinTextEncodingFromLangStr(const OUString& sLanguage, bool bOEM) +{ + return bOEM ? + impl_getWinTextEncodingFromLangStrOEM(sLanguage) : + impl_getWinTextEncodingFromLangStrANSI(sLanguage); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |