summaryrefslogtreecommitdiffstats
path: root/unotools/source/misc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--unotools/source/misc/ServiceDocumenter.cxx89
-rw-r--r--unotools/source/misc/ServiceDocumenter.hxx57
-rw-r--r--unotools/source/misc/ZipPackageHelper.cxx174
-rw-r--r--unotools/source/misc/closeveto.cxx147
-rw-r--r--unotools/source/misc/datetime.cxx529
-rw-r--r--unotools/source/misc/defaultencoding.cxx33
-rw-r--r--unotools/source/misc/desktopterminationobserver.cxx188
-rw-r--r--unotools/source/misc/eventlisteneradapter.cxx155
-rw-r--r--unotools/source/misc/fontcvt.cxx1444
-rw-r--r--unotools/source/misc/fontdefs.cxx575
-rw-r--r--unotools/source/misc/mediadescriptor.cxx497
-rw-r--r--unotools/source/misc/sharedunocomponent.cxx199
-rw-r--r--unotools/source/misc/syslocale.cxx212
-rw-r--r--unotools/source/misc/wincodepage.cxx141
14 files changed, 4440 insertions, 0 deletions
diff --git a/unotools/source/misc/ServiceDocumenter.cxx b/unotools/source/misc/ServiceDocumenter.cxx
new file mode 100644
index 000000000..0bf1ce9fa
--- /dev/null
+++ b/unotools/source/misc/ServiceDocumenter.cxx
@@ -0,0 +1,89 @@
+/* -*- 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 <com/sun/star/system/SystemShellExecuteFlags.hpp>
+#include <com/sun/star/system/XSystemShellExecute.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/supportsservice.hxx>
+
+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);
+ }
+}
+
+// XServiceInfo
+sal_Bool unotools::misc::ServiceDocumenter::supportsService(const OUString& sServiceName)
+{
+ return cppu::supportsService(this, sServiceName);
+}
+OUString unotools::misc::ServiceDocumenter::getImplementationName()
+{
+ return "com.sun.star.comp.unotools.misc.ServiceDocumenter";
+}
+css::uno::Sequence< OUString > unotools::misc::ServiceDocumenter::getSupportedServiceNames()
+{
+ return { "com.sun.star.script.ServiceDocumenter" };
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+unotools_ServiceDocument_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new unotools::misc::ServiceDocumenter(context));
+}
diff --git a/unotools/source/misc/ServiceDocumenter.hxx b/unotools/source/misc/ServiceDocumenter.hxx
new file mode 100644
index 000000000..0c94b5ac7
--- /dev/null
+++ b/unotools/source/misc/ServiceDocumenter.hxx
@@ -0,0 +1,57 @@
+/* -*- 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/.
+ */
+#pragma once
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/script/XServiceDocumenter.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <utility>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace unotools::misc {
+
+class ServiceDocumenter : public ::cppu::WeakImplHelper<
+ css::script::XServiceDocumenter, css::lang::XServiceInfo>
+{
+ public:
+ ServiceDocumenter(css::uno::Reference< css::uno::XComponentContext> xContext)
+ : m_xContext(std::move(xContext))
+ , m_sCoreBaseUrl("http://example.com")
+ , m_sServiceBaseUrl("https://api.libreoffice.org/docs/idl/ref")
+ {};
+
+ // XServiceInfo
+ virtual sal_Bool SAL_CALL supportsService(const OUString& sServiceName) override;
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // 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;
+};
+
+}
+/* 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..c66db0127
--- /dev/null
+++ b/unotools/source/misc/ZipPackageHelper.cxx
@@ -0,0 +1,174 @@
+/* -*- 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 )
+{
+ // create the package zip file
+ Sequence< Any > aArguments{
+ Any(sPackageURL),
+ // let ZipPackage be used
+ Any(beans::NamedValue("StorageFormat", Any(OUString(ZIP_STORAGE_FORMAT_STRING))))
+ };
+
+ 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();
+
+ Reference< XInterface > xFolder( mxFactory->createInstanceWithArguments({ Any(true) } ));
+ 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 ), Any(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..02e5dc5fa
--- /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 );
+ }
+
+ void lcl_deinit( CloseVeto_Data const & i_data )
+ {
+ if ( !i_data.xCloseable.is() )
+ return;
+
+ i_data.xCloseable->removeCloseListener( i_data.pListener );
+ 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..c620307a9
--- /dev/null
+++ b/unotools/source/misc/datetime.cxx
@@ -0,0 +1,529 @@
+/* -*- 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 <o3tl/string_view.hxx>
+#include <cstddef>
+#include <sstream>
+
+namespace
+{
+ bool checkAllNumber(std::u16string_view rString)
+ {
+ sal_Int32 nPos = 0;
+ sal_Int32 nLen = rString.size();
+
+ // 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,
+ std::u16string_view rString,
+ sal_Int32 /*nMin*/ = -1, sal_Int32 /*nMax*/ = -1)
+ {
+ if (!checkAllNumber(rString))
+ {
+ rValue = 0;
+ return false;
+ }
+
+ rValue = o3tl::toInt32(rString);
+ return true;
+ }
+
+ bool convertNumber64(sal_Int64& rValue,
+ std::u16string_view rString,
+ sal_Int64 /*nMin*/ = -1, sal_Int64 /*nMax*/ = -1)
+ {
+ if (!checkAllNumber(rString))
+ {
+ rValue = 0;
+ return false;
+ }
+
+ rValue = o3tl::toInt64(rString);
+ 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(std::u16string_view i_str, std::size_t &nPos, OUString &resInt, bool &bFraction, OUString &resFrac)
+ {
+ bFraction = false;
+ // all tokens are of length 2
+ const std::size_t nEndPos = nPos + 2;
+ const sal_Unicode c0 = '0';
+ const sal_Unicode c9 = '9';
+ const sal_Unicode sep = ':';
+ for (;nPos < nEndPos && nPos < i_str.size(); ++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 == 0)
+ return false;
+ if (nPos == i_str.size() || i_str[nPos] == sep)
+ return true;
+ if (i_str[nPos] == ',' || i_str[nPos] == '.')
+ {
+ bFraction = true;
+ ++nPos;
+ for (; nPos < i_str.size(); ++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.size(), "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(std::u16string_view i_str, std::size_t &io_index, OUString &o_strInt, bool &o_bFraction, OUString &o_strFrac)
+ {
+ OUString resInt;
+ OUString resFrac;
+ bool bFraction = false;
+ std::size_t 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(std::u16string_view i_str, std::size_t &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.size(); ++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(std::u16string_view rString, css::util::DateTime& rDateTime)
+{
+ bool bSuccess = true;
+
+ std::u16string_view aDateStr, aTimeStr;
+ css::util::Date aDate;
+ css::util::Time aTime;
+ size_t nPos = rString.find( 'T' );
+ if ( nPos != std::u16string_view::npos )
+ {
+ aDateStr = rString.substr( 0, nPos );
+ aTimeStr = rString.substr( nPos + 1 );
+ }
+ else
+ aDateStr = rString; // no separator: only date part
+
+ bSuccess = ISO8601parseDate(aDateStr, aDate);
+
+ if ( bSuccess && !aTimeStr.empty() ) // 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(std::u16string_view 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, o3tl::getToken(aDateStr, 0, '-', nIdx ), 0, 9999 ) )
+ return false;
+ if ( nDateTokens >= 2 )
+ if ( !convertNumber32( nMonth, o3tl::getToken(aDateStr, 0, '-', nIdx ), 0, 12 ) )
+ return false;
+ if ( nDateTokens >= 3 )
+ if ( !convertNumber32( nDay, o3tl::getToken(aDateStr, 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(std::u16string_view aTimeStr, css::util::Time& rTime)
+{
+ sal_Int32 nHour = 0;
+ sal_Int32 nMin = 0;
+ sal_Int32 nSec = 0;
+ sal_Int32 nNanoSec = 0;
+
+ std::size_t 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.size())
+ {
+ // 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.size())
+ goto end;
+
+ // minutes
+ bSuccess = getISO8601TimeToken(aTimeStr, n, tokInt, bFrac, tokFrac);
+ if (!bSuccess)
+ return false;
+ if ( bFrac && n < aTimeStr.size())
+ {
+ // 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.size())
+ goto end;
+
+ // seconds
+ bSuccess = getISO8601TimeToken(aTimeStr, n, tokInt, bFrac, tokFrac);
+ if (!bSuccess)
+ return false;
+ if (n < aTimeStr.size())
+ {
+ // 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..b899db5c0
--- /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;
+ }
+
+ rtl::Reference<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..15ea8f2c1
--- /dev/null
+++ b/unotools/source/misc/fontcvt.cxx
@@ -0,0 +1,1444 @@
+/* -*- 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 <cstddef>
+#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)
+
+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
+};
+
+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
+};
+
+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
+};
+
+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
+};
+
+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
+};
+
+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
+
+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,
+};
+
+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,
+};
+
+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,
+};
+
+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 aAggressiveTable[] =
+ {
+ 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(aAggressiveTable);
+
+ for (i = 0; i < nEntries; ++i)
+ {
+ const ExtendedConvertTable& r = aAggressiveTable[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;};
+
+}
+
+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}}
+};
+
+const RecodeTable aAppleSymbolRecodeTable[] = {
+ {"symbol", {aAdobeSymbolToAppleSymbolTab, "AppleSymbol", nullptr}}
+};
+
+static ConvertChar aImplStarSymbolCvt = { nullptr, "StarBats", ImplStarSymbolToStarBats };
+
+const ConvertChar* ConvertChar::GetRecodeData( std::u16string_view rOrgFontName, std::u16string_view 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( std::size_t i = 0; i < 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( std::size_t i = 0; i < 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( std::u16string_view rOrgName, FontToSubsFontFlags nFlags )
+{
+ const ConvertChar* pCvt = nullptr;
+
+ OUString aName = GetEnglishSearchFontName( rOrgName );
+
+ if ( nFlags == FontToSubsFontFlags::IMPORT )
+ {
+ const std::size_t nEntries = 2; // only StarMath+StarBats
+ for( std::size_t 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..568110315
--- /dev/null
+++ b/unotools/source/misc/fontdefs.cxx
@@ -0,0 +1,575 @@
+/* -*- 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 <o3tl/safeint.hxx>
+#include <unotools/fontdefs.hxx>
+#include <unotools/fontcfg.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <string_view>
+#include <unordered_map>
+
+sal_Unicode const aBatang[] = { 0xBC14, 0xD0D5, 0 };
+sal_Unicode const aBatangChe[] = { 0xBC14, 0xD0D5, 0xCCB4, 0 };
+sal_Unicode const aGungsuh[] = { 0xAD81, 0xC11C, 0 };
+sal_Unicode const aGungsuhChe[] = { 0xAD81, 0xC11C, 0xCCB4, 0 };
+sal_Unicode const aGulim[] = { 0xAD74, 0xB9BC, 0 };
+sal_Unicode const aGulimChe[] = { 0xAD74, 0xB9BC, 0xCCB4, 0 };
+sal_Unicode const aDotum[] = { 0xB3CB, 0xC6C0, 0 };
+sal_Unicode const aDotumChe[] = { 0xB3CB, 0xC6C0, 0xCCB4, 0 };
+sal_Unicode const aSimSun[] = { 0x5B8B, 0x4F53, 0 };
+sal_Unicode const aNSimSun[] = { 0x65B0, 0x5B8B, 0x4F53, 0 };
+sal_Unicode const aSimHei[] = { 0x9ED1, 0x4F53, 0 };
+sal_Unicode const aSimKai[] = { 0x6977, 0x4F53, 0 };
+sal_Unicode const azycjkSun[] = { 0x4E2D, 0x6613, 0x5B8B, 0x4F53, 0 };
+sal_Unicode const azycjkHei[] = { 0x4E2D, 0x6613, 0x9ED1, 0x4F53, 0 };
+sal_Unicode const azycjkKai[] = { 0x4E2D, 0x6613, 0x6977, 0x4F53, 0 };
+sal_Unicode const aFZHei[] = { 0x65B9, 0x6B63, 0x9ED1, 0x4F53, 0 };
+sal_Unicode const aFZKai[] = { 0x65B9, 0x6B63, 0x6977, 0x4F53, 0 };
+sal_Unicode const aFZSongYI[] = { 0x65B9, 0x6B63, 0x5B8B, 0x4E00, 0 };
+sal_Unicode const aFZShuSong[] = { 0x65B9, 0x6B63, 0x4E66, 0x5B8B, 0 };
+sal_Unicode const aFZFangSong[] = { 0x65B9, 0x6B63, 0x4EFF, 0x5B8B, 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
+sal_Unicode const aMHei1[] = { 'm', 0x7B80, 0x9ED1, 0 };
+sal_Unicode const aMHei2[] = { 'm', 0x6F60, 0x7AAA, 0 };
+sal_Unicode const aMKai1[] = { 'm', 0x7B80, 0x6977, 0x566C, 0 };
+sal_Unicode const aMKai2[] = { 'm', 0x6F60, 0x7FF1, 0x628E, 0 };
+sal_Unicode const aMSong1[] = { 'm', 0x7B80, 0x5B8B, 0 };
+sal_Unicode const aMSong2[] = { 'm', 0x6F60, 0x51BC, 0 };
+sal_Unicode const aCFangSong1[] = { 'm', 0x7B80, 0x592B, 0x5B8B, 0 };
+sal_Unicode const aCFangSong2[] = { 'm', 0x6F60, 0x6E98, 0x51BC, 0 };
+sal_Unicode const aMingLiU[] = { 0x7D30, 0x660E, 0x9AD4, 0 };
+sal_Unicode const aPMingLiU[] = { 0x65B0, 0x7D30, 0x660E, 0x9AD4, 0 };
+sal_Unicode const aHei[] = { 0x6865, 0 };
+sal_Unicode const aKai[] = { 0x6B61, 0 };
+sal_Unicode const aMing[] = { 0x6D69, 0x6E67, 0 };
+sal_Unicode const aMSGothic[] = { 'm','s', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
+sal_Unicode const aMSPGothic[] = { 'm','s','p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
+sal_Unicode const aMSMincho[] = { 'm', 's', 0x660E, 0x671D, 0 };
+sal_Unicode const aMSPMincho[] = { 'm','s','p', 0x660E, 0x671D, 0 };
+sal_Unicode const aMSYaHei[] = { 0x5FAE, 0x8F6F, 0x96C5, 0x9ED1, 0 };
+sal_Unicode const aMSJhengHei[] = { 0x5FAE, 0x8EDF, 0x6B63, 0x9ED1, 0x9AD4, 0 };
+sal_Unicode const aMeiryo[] = { 0x30e1, 0x30a4, 0x30ea, 0x30aa, 0 };
+sal_Unicode const aHGMinchoL[] = { 'h','g', 0x660E, 0x671D, 'l', 0 };
+sal_Unicode const aHGGothicB[] = { 'h','g', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 0 };
+sal_Unicode const aHGPMinchoL[] = { 'h','g','p', 0x660E, 0x671D, 'l', 0 };
+sal_Unicode const aHGPGothicB[] = { 'h','g','p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 0 };
+sal_Unicode const aHGMinchoLSun[] = { 'h','g', 0x660E, 0x671D, 'l', 's', 'u', 'n', 0 };
+sal_Unicode const aHGPMinchoLSun[] = { 'h','g','p', 0x660E, 0x671D, 'l', 's', 'u', 'n', 0 };
+sal_Unicode const aHGGothicBSun[] = { 'h', 'g', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 's', 'u', 'n', 0 };
+sal_Unicode const aHGPGothicBSun[] = { 'h', 'g', 'p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 's', 'u', 'n', 0 };
+sal_Unicode const aHGHeiseiMin1[] = { 'h', 'g', 0x5E73, 0x6210, 0x660E, 0x671D, 0x4F53, 0 };
+sal_Unicode const aHGHeiseiMin2[] = { 'h', 'g', 0x5E73, 0x6210, 0x660E, 0x671D, 0x4F53, 'w', '3', 'x', '1', '2', 0 };
+sal_Unicode const aIPAMincho[] = { 'i', 'p', 'a', 0x660E, 0x671D, 0 };
+sal_Unicode const aIPAPMincho[] = { 'i', 'p', 'a', 'p', 0x660E, 0x671D, 0 };
+sal_Unicode const aIPAGothic[] = { 'i', 'p', 'a', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
+sal_Unicode const aIPAPGothic[] = { 'i', 'p', 'a', 'p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
+sal_Unicode const aIPAUIGothic[] = { 'i', 'p', 'a', 'u', 'i', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
+sal_Unicode const aTakaoMincho[] = { 't', 'a', 'k', 'a', 'o', 0x660E, 0x671D, 0 };
+sal_Unicode const aTakaoPMincho[] = { 't', 'a', 'k', 'a', 'o', 'p', 0x660E, 0x671D, 0 };
+sal_Unicode const aTakaoGothic[] = { 't', 'a', 'k', 'a', 'o', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
+sal_Unicode const aTakaoPGothic[] = { 't', 'a', 'k', 'a', 'o', 'p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
+sal_Unicode const aSazanamiMincho[] = { 0x3055, 0x3056, 0x306A, 0x307F, 0x660E, 0x671D, 0 };
+sal_Unicode const aSazanamiGothic[] = { 0x3055, 0x3056, 0x306A, 0x307F, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
+sal_Unicode const aKochiMincho[] = { 0x6771, 0x98A8, 0x660E, 0x671D, 0 };
+sal_Unicode const aKochiGothic[] = { 0x6771, 0x98A8, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
+sal_Unicode const aSunDotum[] = { 0xC36C, 0xB3CB, 0xC6C0, 0 };
+sal_Unicode const aSunGulim[] = { 0xC36C, 0xAD74, 0xB9BC, 0 };
+sal_Unicode const aSunBatang[] = { 0xC36C, 0xBC14, 0xD0D5, 0 };
+sal_Unicode const aBaekmukDotum[] = { 0xBC31, 0xBB35, 0xB3CB, 0xC6C0, 0 };
+sal_Unicode const aBaekmukGulim[] = { 0xBC31, 0xBB35, 0xAD74, 0xB9BC, 0 };
+sal_Unicode const aBaekmukBatang[] = { 0xBC31, 0xBB35, 0xBC14, 0xD0D5, 0 };
+sal_Unicode const aFzMingTi[] = { 0x65B9, 0x6B63, 0x660E, 0x9AD4, 0 };
+sal_Unicode const aFzHeiTiTW[]= { 0x65B9, 0x6B63, 0x9ED1, 0x9AD4, 0 };
+sal_Unicode const aFzKaiTiTW[]= { 0x65B9, 0x6B63, 0x6977, 0x9AD4, 0 };
+sal_Unicode const aFzHeiTiCN[]= { 0x65B9, 0x6B63, 0x9ED1, 0x4F53, 0 };
+sal_Unicode const aFzKaiTiCN[]= { 0x65B9, 0x6B63, 0x6977, 0x4F53, 0 };
+sal_Unicode const aFzSongTi[] = { 0x65B9, 0x6B63, 0x5B8B, 0x4F53, 0 };
+sal_Unicode const aHYMyeongJoExtra[] = { 'h', 'y', 0xACAC, 0xBA85, 0xC870, 0 };
+sal_Unicode const aHYSinMyeongJoMedium[] = { 'h', 'y', 0xC2E0, 0xBA85, 0xC870, 0 };
+sal_Unicode const aHYGothicMedium[] = { 'h', 'y', 0xC911, 0xACE0, 0xB515, 0 };
+sal_Unicode const aHYGraphicMedium[] = { 'h', 'y', 0xADF8, 0xB798, 0xD53D, 'm', 0 };
+sal_Unicode const aHYGraphic[] = { 'h', 'y', 0xADF8, 0xB798, 0xD53D, 0 };
+sal_Unicode const aNewGulim[] = { 0xC0C8, 0xAD74, 0xB9BC, 0 };
+sal_Unicode const aSunGungseo[] = { 0xC36C, 0xAD81, 0xC11C, 0 };
+sal_Unicode const aHYGungSoBold[] = { 'h','y', 0xAD81, 0xC11C, 'b', 0 };
+sal_Unicode const aHYGungSo[] = { 'h','y', 0xAD81, 0xC11C, 0 };
+sal_Unicode const aSunHeadLine[] = { 0xC36C, 0xD5E4, 0xB4DC, 0xB77C, 0xC778, 0 };
+sal_Unicode const aHYHeadLineMedium[] = { 'h', 'y', 0xD5E4, 0xB4DC, 0xB77C, 0xC778, 'm', 0 };
+sal_Unicode const aHYHeadLine[] = { 'h', 'y', 0xD5E4, 0xB4DC, 0xB77C, 0xC778, 0 };
+sal_Unicode const aYetR[] = { 0xD734, 0xBA3C, 0xC61B, 0xCCB4, 0 };
+sal_Unicode const aHYGothicExtra[] = { 'h', 'y', 0xACAC, 0xACE0, 0xB515, 0 };
+sal_Unicode const aSunMokPan[] = { 0xC36C, 0xBAA9, 0xD310, 0 };
+sal_Unicode const aSunYeopseo[] = { 0xC36C, 0xC5FD, 0xC11C, 0 };
+sal_Unicode const aSunBaekSong[] = { 0xC36C, 0xBC31, 0xC1A1, 0 };
+sal_Unicode const aHYPostLight[] = { 'h', 'y', 0xC5FD, 0xC11C, 'l', 0 };
+sal_Unicode const aHYPost[] = { 'h', 'y', 0xC5FD, 0xC11C, 0 };
+sal_Unicode const aMagicR[] = { 0xD734, 0xBA3C, 0xB9E4, 0xC9C1, 0xCCB4, 0 };
+sal_Unicode const aSunCrystal[] = { 0xC36C, 0xD06C, 0xB9AC, 0xC2A4, 0xD0C8, 0 };
+sal_Unicode const aSunSaemmul[] = { 0xC36C, 0xC0D8, 0xBB3C, 0 };
+sal_Unicode const aHaansoftBatang[] = { 0xD55C, 0xCEF4, 0xBC14, 0xD0D5, 0 };
+sal_Unicode const aHaansoftDotum[] = { 0xD55C, 0xCEF4, 0xB3CB, 0xC6C0, 0 };
+sal_Unicode const aHyhaeseo[] = { 0xD55C, 0xC591, 0xD574, 0xC11C, 0 };
+sal_Unicode const aMDSol[] = { 'm', 'd', 0xC194, 0xCCB4, 0 };
+sal_Unicode const aMDGaesung[] = { 'm', 'd', 0xAC1C, 0xC131, 0xCCB4, 0 };
+sal_Unicode const aMDArt[] = { 'm', 'd', 0xC544, 0xD2B8, 0xCCB4, 0 };
+sal_Unicode const aMDAlong[] = { 'm', 'd', 0xC544, 0xB871, 0xCCB4, 0 };
+sal_Unicode const aMDEasop[] = { 'm', 'd', 0xC774, 0xC19D, 0xCCB4, 0 };
+sal_Unicode const aHYShortSamulMedium[] = { 'h', 'y', 0xC595, 0xC740, 0xC0D8, 0xBB3C, 'm', 0 };
+sal_Unicode const aHYShortSamul[] = { 'h', 'y', 0xC595, 0xC740, 0xC0D8, 0xBB3C, 0 };
+sal_Unicode const aHGGothicE[] = { 'h','g', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'e', 0 };
+sal_Unicode const aHGPGothicE[] = { 'h','g','p', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'e', 0 };
+sal_Unicode const aHGSGothicE[] = { 'h','g','s', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'e', 0 };
+sal_Unicode const aHGGothicM[] = { 'h','g', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'm', 0 };
+sal_Unicode const aHGPGothicM[] = { 'h','g','p', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'm', 0 };
+sal_Unicode const aHGSGothicM[] = { 'h','g','s', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'm', 0 };
+sal_Unicode const aHGGyoshotai[] = { 'h','g', 0x884C, 0x66F8, 0x4F53, 0 };
+sal_Unicode const aHGPGyoshotai[] = { 'h','g','p', 0x884C, 0x66F8, 0x4F53, 0 };
+sal_Unicode const aHGSGyoshotai[] = { 'h','g','s', 0x884C, 0x66F8, 0x4F53, 0 };
+sal_Unicode const aHGKyokashotai[] = { 'h','g', 0x6559, 0x79D1, 0x66F8, 0x4F53, 0 };
+sal_Unicode const aHGPKyokashotai[] = { 'h','g','p', 0x6559, 0x79D1, 0x66F8, 0x4F53, 0 };
+sal_Unicode const aHGSKyokashotai[] = { 'h','g','s', 0x6559, 0x79D1, 0x66F8, 0x4F53, 0 };
+sal_Unicode const aHGMinchoB[] = { 'h','g', 0x660E, 0x671D, 'b', 0 };
+sal_Unicode const aHGPMinchoB[] = { 'h','g','p', 0x660E, 0x671D, 'b', 0 };
+sal_Unicode const aHGSMinchoB[] = { 'h','g','s', 0x660E, 0x671D, 'b', 0 };
+sal_Unicode const aHGMinchoE[] = { 'h','g', 0x660E, 0x671D, 'e', 0 };
+sal_Unicode const aHGPMinchoE[] = { 'h','g','p', 0x660E, 0x671D, 'e', 0 };
+sal_Unicode const aHGSMinchoE[] = { 'h','g','s', 0x660E, 0x671D, 'e', 0 };
+sal_Unicode const aHGSoeiKakupoptai[] = { 'h','g', 0x5275,0x82F1,0x89D2,0xFF8E,
+ 0xFF9F,0xFF6F,0xFF8C,0xFF9F,0x4F53,0};
+sal_Unicode const aHGPSoeiKakupoptai[] = { 'h','g', 'p', 0x5275,0x82F1,0x89D2,0xFF8E,
+ 0xFF9F,0xFF6F,0xFF8C,0xFF9F,0x4F53,0};
+sal_Unicode const aHGSSoeiKakupoptai[] = { 'h','g', 's', 0x5275,0x82F1,0x89D2,0xFF8E,
+ 0xFF9F,0xFF6F,0xFF8C,0xFF9F,0x4F53,0};
+sal_Unicode const aHGSoeiPresenceEB[] = { 'h','g', 0x5275,0x82F1,0xFF8C,0xFF9F,
+ 0xFF9A,0xFF7E,0xFF9E,0xFF9D,0xFF7D, 'e','b',0};
+sal_Unicode const aHGPSoeiPresenceEB[] = { 'h','g','p', 0x5275,0x82F1,0xFF8C,0xFF9F,
+ 0xFF9A,0xFF7E,0xFF9E,0xFF9D,0xFF7D, 'e','b',0};
+sal_Unicode const aHGSSoeiPresenceEB[] = { 'h','g','s', 0x5275,0x82F1,0xFF8C,0xFF9F,
+ 0xFF9A,0xFF7E,0xFF9E,0xFF9D,0xFF7D, 'e','b',0};
+sal_Unicode const aHGSoeiKakugothicUB[] = { 'h','g', 0x5275,0x82F1,0x89D2,0xFF7A,
+ 0xFF9E,0xFF7C,0xFF6F,0xFF78,'u','b',0};
+sal_Unicode const aHGPSoeiKakugothicUB[] = { 'h','g','p', 0x5275,0x82F1,0x89D2,0xFF7A,
+ 0xFF9E,0xFF7C,0xFF6F,0xFF78,'u','b',0};
+sal_Unicode const aHGSSoeiKakugothicUB[] = { 'h','g','s', 0x5275,0x82F1,0x89D2,0xFF7A,
+ 0xFF9E,0xFF7C,0xFF6F,0xFF78,'u','b',0};
+sal_Unicode const aHGSeikaishotaiPRO[] = { 'h','g', 0x6B63,0x6977,0x66F8,0x4F53, '-','p','r','o',0};
+sal_Unicode const aHGMaruGothicMPRO[] = { 'h','g', 0x4E38,0xFF7A,0xFF9E,0xFF7C,0xFF6F,0xFF78, '-','p','r','o',0};
+sal_Unicode const aHiraginoMinchoPro[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x660E, 0x671D, 'p','r','o',0};
+sal_Unicode const aHiraginoMinchoProN[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x660E, 0x671D, 'p','r','o','n',0};
+sal_Unicode const aHiraginoKakuGothic[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x89D2, 0x30B4, 0x30B7, 0x30C3, 0x30AF,0};
+sal_Unicode const aHiraginoKakuGothicPro[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x89D2, 0x30B4, 'p','r','o',0};
+sal_Unicode const aHiraginoKakuGothicProN[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x89D2, 0x30B4, 'p','r','o','n',0};
+sal_Unicode const aHiraginoMaruGothicPro[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x4E38, 0x30B4, 'p','r','o',0};
+sal_Unicode const aHiraginoMaruGothicProN[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x4E38, 0x30B4, 'p','r','o','n',0};
+sal_Unicode const aYuGothic[] = { 0x6E38, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0};
+sal_Unicode const aYuGothicTai[] = { 0x6E38, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0x4F53, 0};
+sal_Unicode const aYuMincho[] = { 0x6E38, 0x660E, 0x671D, 0};
+sal_Unicode const aYuMinchoTai[] = { 0x6E38, 0x660E, 0x671D, 0x4F53, 0};
+sal_Unicode const aGennoKakuGothic[] = { 0x6E90, 0x30CE, 0x89D2, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0};
+sal_Unicode const aGennoKakuGothicJP[] = { 0x6E90, 0x30CE, 0x89D2, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'j', 'p', 0};
+sal_Unicode const aGennoKakuGothicHW[] = { 0x6E90, 0x30CE, 0x89D2, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'h','w', 0};
+sal_Unicode const aGennoMincho[] = { 0x6E90, 0x30CE, 0x660E, 0x671D, 0};
+sal_Unicode const aGennoMinchoJP[] = { 0x6E90, 0x30CE, 0x660E, 0x671D, 'j', 'p', 0};
+sal_Unicode const aIPAmjMincho[] = { 'i', 'p', 'a', 'm', 'j', 0x660E, 0x671D, 0};
+sal_Unicode const aIPAexGothic[] = { 'i', 'p', 'a', 'e', 'x', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0};
+sal_Unicode const aIPAexMincho[] = { 'i', 'p', 'a', 'e', 'x', 0x660E, 0x671D, 0};
+
+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(std::u16string_view 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, OUString> FontNameDictionary;
+ static FontNameDictionary const aDictionary = {
+ {aBatang, "batang"},
+ {aBatangChe, "batangche"},
+ {aGungsuh, "gungshu"},
+ {aGungsuhChe, "gungshuche"},
+ {aGulim, "gulim"},
+ {aGulimChe, "gulimche"},
+ {aDotum, "dotum"},
+ {aDotumChe, "dotumche"},
+ {aSimSun, "simsun"},
+ {aNSimSun, "nsimsun"},
+ {aSimHei, "simhei"},
+ {aSimKai, "simkai"},
+ {azycjkSun, "zycjksun"},
+ {azycjkHei, "zycjkhei"},
+ {azycjkKai, "zycjkkai"},
+ {aFZHei, "fzhei"},
+ {aFZKai, "fzkai"},
+ {aFZSongYI, "fzsong"},
+ {aFZShuSong, "fzshusong"},
+ {aFZFangSong, "fzfangsong"},
+ {aMHei1, "mhei"},
+ {aMHei2, "mhei"},
+ {aMKai1, "mkai"},
+ {aMKai2, "mkai"},
+ {aMSong1, "msong"},
+ {aMSong2, "msong"},
+ {aCFangSong1, "cfangsong"},
+ {aCFangSong2, "cfangsong"},
+ {aMingLiU, "mingliu"},
+ {aPMingLiU, "pmingliu"},
+ {aHei, "hei"},
+ {aKai, "kai"},
+ {aMing, "ming"},
+ {aMSGothic, "msgothic"},
+ {aMSPGothic, "mspgothic"},
+ {aMSMincho, "msmincho"},
+ {aMSPMincho, "mspmincho"},
+ {aMSJhengHei, "microsoftjhenghei"},
+ {aMSYaHei, "microsoftyahei"},
+ {aMeiryo, "meiryo"},
+ {aHGMinchoL, "hgminchol"},
+ {aHGGothicB, "hggothicb"},
+ {aHGPMinchoL, "hgpminchol"},
+ {aHGPGothicB, "hgpgothicb"},
+ {aHGMinchoLSun, "hgmincholsun"},
+ {aHGGothicBSun, "hggothicbsun"},
+ {aHGPMinchoLSun, "hgpmincholsun"},
+ {aHGPGothicBSun, "hgpgothicbsun"},
+ {aHGHeiseiMin1, "hgheiseimin"},
+ {aHGHeiseiMin2, "hgheiseimin"},
+ {aIPAMincho, "ipamincho"},
+ {aIPAPMincho, "ipapmincho"},
+ {aIPAGothic, "ipagothic"},
+ {aIPAPGothic, "ipapgothic"},
+ {aIPAUIGothic, "ipauigothic"},
+ {aTakaoMincho, "takaomincho"},
+ {aTakaoPMincho, "takaopmincho"},
+ {aTakaoGothic, "takaogothic"},
+ {aTakaoPGothic, "takaopgothic"},
+ {aSazanamiMincho, "sazanamimincho"},
+ {aSazanamiGothic, "sazanamigothic"},
+ {aKochiMincho, "kochimincho"},
+ {aKochiGothic, "kochigothic"},
+ {aSunDotum, "sundotum"},
+ {aSunGulim, "sungulim"},
+ {aSunBatang, "sunbatang"},
+ {aBaekmukDotum, "baekmukdotum"},
+ {aBaekmukGulim, "baekmukgulim"},
+ {aBaekmukBatang, "baekmukbatang"},
+ {aFzHeiTiCN, "fzheiti"},
+ {aFzHeiTiTW, "fzheiti"},
+ {aFzKaiTiCN, "fzkaiti"},
+ {aFzKaiTiTW, "fzkaitib"},
+ {aFzMingTi, "fzmingtib"},
+ {aFzSongTi, "fzsongti"},
+ {aHYMyeongJoExtra, "hymyeongjoextra"},
+ {aHYSinMyeongJoMedium, "hysinmyeongjomedium"},
+ {aHYGothicMedium, "hygothicmedium"},
+ {aHYGraphicMedium, "hygraphicmedium"},
+ {aHYGraphic, "hygraphic"},
+ {aNewGulim, "newgulim"},
+ {aSunGungseo, "sungungseo"},
+ {aHYGungSoBold, "hygungsobold"},
+ {aHYGungSo, "hygungso"},
+ {aSunHeadLine, "sunheadline"},
+ {aHYHeadLineMedium, "hyheadlinemedium"},
+ {aHYHeadLine, "hyheadline"},
+ {aYetR, "yetr"},
+ {aHYGothicExtra, "hygothicextra"},
+ {aSunMokPan, "sunmokpan"},
+ {aSunYeopseo, "sunyeopseo"},
+ {aSunBaekSong, "sunbaeksong"},
+ {aHYPostLight, "hypostlight"},
+ {aHYPost, "hypost"},
+ {aMagicR, "magicr"},
+ {aSunCrystal, "suncrystal"},
+ {aSunSaemmul, "sunsaemmul"},
+ {aHYShortSamulMedium, "hyshortsamulmedium"},
+ {aHYShortSamul, "hyshortsamul"},
+ {aHaansoftBatang, "haansoftbatang"},
+ {aHaansoftDotum, "haansoftdotum"},
+ {aHyhaeseo, "hyhaeseo"},
+ {aMDSol, "mdsol"},
+ {aMDGaesung, "mdgaesung"},
+ {aMDArt, "mdart"},
+ {aMDAlong, "mdalong"},
+ {aMDEasop, "mdeasop"},
+ {aHGGothicE, "hggothice"},
+ {aHGPGothicE, "hgpgothice"},
+ {aHGSGothicE, "hgsgothice"},
+ {aHGGothicM, "hggothicm"},
+ {aHGPGothicM, "hgpgothicm"},
+ {aHGSGothicM, "hgsgothicm"},
+ {aHGGyoshotai, "hggyoshotai"},
+ {aHGPGyoshotai, "hgpgyoshotai"},
+ {aHGSGyoshotai, "hgsgyoshotai"},
+ {aHGKyokashotai, "hgkyokashotai"},
+ {aHGPKyokashotai, "hgpkyokashotai"},
+ {aHGSKyokashotai, "hgskyokashotai"},
+ {aHGMinchoB, "hgminchob"},
+ {aHGPMinchoB, "hgpminchob"},
+ {aHGSMinchoB, "hgsminchob"},
+ {aHGMinchoE, "hgminchoe"},
+ {aHGPMinchoE, "hgpminchoe"},
+ {aHGSMinchoE, "hgsminchoe"},
+ {aHGSoeiKakupoptai, "hgsoeikakupoptai"},
+ {aHGPSoeiKakupoptai, "hgpsoeikakupopta"},
+ {aHGSSoeiKakupoptai, "hgssoeikakupopta"},
+ {aHGSoeiPresenceEB, "hgsoeipresenceeb"},
+ {aHGPSoeiPresenceEB, "hgpsoeipresenceeb"},
+ {aHGSSoeiPresenceEB, "hgssoeipresenceeb"},
+ {aHGSoeiKakugothicUB, "hgsoeikakugothicub"},
+ {aHGPSoeiKakugothicUB, "hgpsoeikakugothicub"},
+ {aHGSSoeiKakugothicUB, "hgssoeikakugothicub"},
+ {aHGSeikaishotaiPRO, "hgseikaishotaipro"},
+ {aHGMaruGothicMPRO, "hgmarugothicmpro"},
+ {aHiraginoMinchoPro, "hiraginominchopro"},
+ {aHiraginoMinchoProN, "hiraginominchopron"},
+ {aHiraginoKakuGothic, "hiraginosans"},
+ {aHiraginoKakuGothicPro, "hiraginokakugothicpro"},
+ {aHiraginoKakuGothicProN, "hiraginokakugothicpron"},
+ {aHiraginoMaruGothicPro, "hiraginomarugothicpro"},
+ {aHiraginoMaruGothicProN, "hiraginomarugothicpron"},
+ {aHiraginoMaruGothicProN, "hiraginomarugothicpron"},
+ {aYuGothic, "yugothic"},
+ {aYuGothicTai, "yugothictai"},
+ {aYuMincho, "yumincho"},
+ {aYuMinchoTai, "yuminchotai"},
+ {aGennoKakuGothic, "sourcehansans"},
+ {aGennoKakuGothicJP, "sourcehansansjp"},
+ {aGennoKakuGothicHW, "sourcehansanshw"},
+ {aGennoMincho, "sourcehanserif"},
+ {aGennoMinchoJP, "sourcehanserifjp"},
+ {aIPAmjMincho, "ipamjmincho"},
+ {aIPAexGothic, "ipaexgothic"},
+ {aIPAexMincho, "ipaexmimcho"}};
+
+ FontNameDictionary::const_iterator it = aDictionary.find( rNameStr );
+ if( it != aDictionary.end() )
+ rNameStr = it->second;
+ }
+
+ return rNameStr;
+}
+
+std::u16string_view GetNextFontToken( std::u16string_view rTokenStr, sal_Int32& rIndex )
+{
+ // check for valid start index
+ size_t nStringLen = rTokenStr.size();
+ if( o3tl::make_unsigned(rIndex) >= nStringLen )
+ {
+ rIndex = -1;
+ return {};
+ }
+
+ // find the next token delimiter and return the token substring
+ const sal_Unicode* pStr = rTokenStr.data() + rIndex;
+ const sal_Unicode* pEnd = rTokenStr.data() + 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.data());
+ 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.substr( nTokenStart, nTokenLen );
+}
+
+static bool ImplIsFontToken( std::u16string_view rName, std::u16string_view 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, std::u16string_view rNewToken )
+{
+ if ( !rName.isEmpty() )
+ {
+ rName += ";";
+ }
+ rName += rNewToken;
+}
+
+void AddTokenFontName( OUString& rName, std::u16string_view rNewToken )
+{
+ if ( !ImplIsFontToken( rName, rNewToken ) )
+ ImplAppendFontToken( rName, rNewToken );
+}
+
+OUString GetSubsFontName( std::u16string_view 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;
+
+ if (nFlags & SubsFontFlags::MS)
+ {
+ const utl::FontNameAttr* pAttr = utl::FontSubstConfiguration::get().getSubstInfo( aOrgName );
+ if (pAttr)
+ for( const auto& rSubstitution : pAttr->MSSubstitutions )
+ if( ! ImplIsFontToken( rName, rSubstitution ) )
+ {
+ ImplAppendFontToken( aName, rSubstitution );
+ if( nFlags & SubsFontFlags::ONLYONE )
+ {
+ break;
+ }
+ }
+ }
+
+ return aName;
+}
+
+bool IsStarSymbol(std::u16string_view 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..3b848817e
--- /dev/null
+++ b/unotools/source/misc/mediadescriptor.cxx
@@ -0,0 +1,497 @@
+/* -*- 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/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;
+ }
+}
+
+}
+
+MediaDescriptor::MediaDescriptor()
+{
+}
+
+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() )
+ return;
+
+ 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&)
+ {
+ TOOLS_WARN_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;
+ rtl::Reference<::ucbhelper::CommandEnvironment> xCommandEnv = new ::ucbhelper::CommandEnvironment(xInteraction, xProgress);
+
+ // 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::Any( 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 >());
+
+ rtl::Reference<comphelper::StillReadWriteInteraction> xInteraction = new comphelper::StillReadWriteInteraction(xOrgInteraction,xAuthenticationInteraction);
+
+ css::uno::Reference< css::ucb::XProgressHandler > xProgress;
+ rtl::Reference<::ucbhelper::CommandEnvironment> xCommandEnv = new ::ucbhelper::CommandEnvironment(xInteraction, xProgress);
+
+ // 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 (!xInteraction->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;
+
+ xInteraction->resetInterceptions();
+ xInteraction->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..41a383d10
--- /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& )
+ {
+ TOOLS_WARN_EXCEPTION( "unotools", "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..a1325958a
--- /dev/null
+++ b/unotools/source/misc/syslocale.cxx
@@ -0,0 +1,212 @@
+/* -*- 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 <rtl/tencinfo.h>
+#include <rtl/locale.h>
+#include <osl/thread.h>
+#include <osl/nlsupport.h>
+
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <vector>
+
+using namespace osl;
+using namespace com::sun::star;
+
+namespace {
+
+std::weak_ptr<SvtSysLocale_Impl> g_pSysLocale;
+
+// static
+std::mutex& 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 std::mutex* persistentMutex(new std::mutex);
+
+ return *persistentMutex;
+}
+
+
+}
+
+class SvtSysLocale_Impl : public utl::ConfigurationListener
+{
+public:
+ SvtSysLocaleOptions aSysLocaleOptions;
+ std::optional<LocaleDataWrapper> moLocaleData;
+ std::optional<CharClass> moCharClass;
+
+ SvtSysLocale_Impl();
+ virtual ~SvtSysLocale_Impl() override;
+
+ CharClass& GetCharClass();
+ virtual void ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints ) override;
+
+private:
+ std::vector<OUString> getDateAcceptancePatternsConfig() const;
+};
+
+SvtSysLocale_Impl::SvtSysLocale_Impl()
+{
+ moLocaleData.emplace(
+ aSysLocaleOptions.GetRealLanguageTag(),
+ getDateAcceptancePatternsConfig() );
+
+ // listen for further changes
+ aSysLocaleOptions.AddListener( this );
+}
+
+SvtSysLocale_Impl::~SvtSysLocale_Impl()
+{
+ aSysLocaleOptions.RemoveListener( this );
+}
+
+CharClass& SvtSysLocale_Impl::GetCharClass()
+{
+ if ( !moCharClass )
+ moCharClass.emplace( aSysLocaleOptions.GetRealLanguageTag() );
+ return *moCharClass;
+}
+
+void SvtSysLocale_Impl::ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints nHint )
+{
+ if ( !(nHint & ConfigurationHints::Locale) &&
+ !(nHint & ConfigurationHints::DatePatterns) )
+ return;
+
+ std::unique_lock aGuard( GetMutex() );
+
+ const LanguageTag& rLanguageTag = aSysLocaleOptions.GetRealLanguageTag();
+ if ( nHint & ConfigurationHints::Locale )
+ {
+ moCharClass.emplace( rLanguageTag );
+ }
+ moLocaleData.emplace(rLanguageTag, getDateAcceptancePatternsConfig());
+}
+
+std::vector<OUString> SvtSysLocale_Impl::getDateAcceptancePatternsConfig() const
+{
+ OUString aStr( aSysLocaleOptions.GetDatePatternsConfigString());
+ if (aStr.isEmpty())
+ return {}; // reset
+ ::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);
+ }
+ return aVec;
+}
+
+SvtSysLocale::SvtSysLocale()
+{
+ std::unique_lock aGuard( GetMutex() );
+ pImpl = g_pSysLocale.lock();
+ if ( !pImpl )
+ {
+ pImpl = std::make_shared<SvtSysLocale_Impl>();
+ g_pSysLocale = pImpl;
+ }
+}
+
+SvtSysLocale::~SvtSysLocale()
+{
+ std::unique_lock aGuard( GetMutex() );
+ pImpl.reset();
+}
+
+const LocaleDataWrapper& SvtSysLocale::GetLocaleData() const
+{
+ return *(pImpl->moLocaleData);
+}
+
+const CharClass& SvtSysLocale::GetCharClass() 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/wincodepage.cxx b/unotools/source/misc/wincodepage.cxx
new file mode 100644
index 000000000..79353e47c
--- /dev/null
+++ b/unotools/source/misc/wincodepage.cxx
@@ -0,0 +1,141 @@
+/* -*- 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 <string_view>
+
+#include <unotools/wincodepage.hxx>
+#include <rtl/textenc.h>
+
+namespace{
+
+struct LangEncodingDef
+{
+ const std::u16string_view 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[] =
+ {
+ { u"en", RTL_TEXTENCODING_MS_1252 }, // Most used -> first in list
+ { u"th", RTL_TEXTENCODING_MS_874 },
+ { u"ja", RTL_TEXTENCODING_MS_932 },
+ { u"zh-cn", RTL_TEXTENCODING_MS_936 }, // Chinese (simplified) - must go before "zh"
+ { u"ko", RTL_TEXTENCODING_MS_949 },
+ { u"zh", RTL_TEXTENCODING_MS_950 }, // Chinese (traditional)
+ { u"bs", RTL_TEXTENCODING_MS_1250 },
+ { u"cs", RTL_TEXTENCODING_MS_1250 },
+ { u"hr", RTL_TEXTENCODING_MS_1250 },
+ { u"hu", RTL_TEXTENCODING_MS_1250 },
+ { u"pl", RTL_TEXTENCODING_MS_1250 },
+ { u"ro", RTL_TEXTENCODING_MS_1250 },
+ { u"sk", RTL_TEXTENCODING_MS_1250 },
+ { u"sl", RTL_TEXTENCODING_MS_1250 },
+// { "sr", RTL_TEXTENCODING_MS_1250 },
+ { u"sq", RTL_TEXTENCODING_MS_1250 },
+ { u"be", RTL_TEXTENCODING_MS_1251 },
+ { u"bg", RTL_TEXTENCODING_MS_1251 },
+ { u"mk", RTL_TEXTENCODING_MS_1251 },
+ { u"ru", RTL_TEXTENCODING_MS_1251 },
+ { u"sr", RTL_TEXTENCODING_MS_1251 },
+ { u"uk", RTL_TEXTENCODING_MS_1251 },
+ { u"es", RTL_TEXTENCODING_MS_1252 },
+ { u"el", RTL_TEXTENCODING_MS_1253 },
+ { u"tr", RTL_TEXTENCODING_MS_1254 },
+ { u"he", RTL_TEXTENCODING_MS_1255 },
+ { u"ar", RTL_TEXTENCODING_MS_1256 },
+ { u"et", RTL_TEXTENCODING_MS_1257 },
+ { u"lt", RTL_TEXTENCODING_MS_1257 },
+ { u"lv", RTL_TEXTENCODING_MS_1257 },
+ { u"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[] =
+ {
+ { u"de", RTL_TEXTENCODING_IBM_437 }, // OEM United States
+ { u"en-us", RTL_TEXTENCODING_IBM_437 }, // OEM United States
+ { u"fi", RTL_TEXTENCODING_IBM_437 }, // OEM United States
+ { u"fr-ca", RTL_TEXTENCODING_IBM_863 }, // OEM French Canadian; French Canadian (DOS)
+ { u"fr", RTL_TEXTENCODING_IBM_437 }, // OEM United States
+ { u"it", RTL_TEXTENCODING_IBM_437 }, // OEM United States
+ { u"nl", RTL_TEXTENCODING_IBM_437 }, // OEM United States
+ { u"sv", RTL_TEXTENCODING_IBM_437 }, // OEM United States
+ { u"el", RTL_TEXTENCODING_IBM_737 }, // OEM Greek (formerly 437G); Greek (DOS)
+ { u"et", RTL_TEXTENCODING_IBM_775 }, // OEM Baltic; Baltic (DOS)
+ { u"lt", RTL_TEXTENCODING_IBM_775 }, // OEM Baltic; Baltic (DOS)
+ { u"lv", RTL_TEXTENCODING_IBM_775 }, // OEM Baltic; Baltic (DOS)
+ { u"en", RTL_TEXTENCODING_IBM_850 }, // OEM Multilingual Latin 1; Western European (DOS)
+ { u"bs", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS)
+ { u"cs", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS)
+ { u"hr", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS)
+ { u"hu", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS)
+ { u"pl", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS)
+ { u"ro", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS)
+ { u"sk", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS)
+ { u"sl", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS)
+// { "sr", RTL_TEXTENCODING_IBM_852 }, // OEM Latin 2; Central European (DOS)
+ { u"bg", RTL_TEXTENCODING_IBM_855 }, // OEM Cyrillic (primarily Russian)
+ { u"mk", RTL_TEXTENCODING_IBM_855 }, // OEM Cyrillic (primarily Russian)
+ { u"sr", RTL_TEXTENCODING_IBM_855 }, // OEM Cyrillic (primarily Russian)
+ { u"tr", RTL_TEXTENCODING_IBM_857 }, // OEM Turkish; Turkish (DOS)
+ { u"pt", RTL_TEXTENCODING_IBM_860 }, // OEM Portuguese; Portuguese (DOS)
+ { u"is", RTL_TEXTENCODING_IBM_861 }, // OEM Icelandic; Icelandic (DOS)
+ { u"he", RTL_TEXTENCODING_IBM_862 }, // OEM Hebrew; Hebrew (DOS)
+ { u"ar", RTL_TEXTENCODING_IBM_864 }, // OEM Arabic; Arabic (864)
+ { u"da", RTL_TEXTENCODING_IBM_865 }, // OEM Nordic; Nordic (DOS)
+ { u"nn", RTL_TEXTENCODING_IBM_865 }, // OEM Nordic; Nordic (DOS)
+ { u"be", RTL_TEXTENCODING_IBM_866 }, // OEM Russian; Cyrillic (DOS)
+ { u"ru", RTL_TEXTENCODING_IBM_866 }, // OEM Russian; Cyrillic (DOS)
+ { u"uk", RTL_TEXTENCODING_IBM_866 }, // OEM Russian; Cyrillic (DOS)
+ { u"th", RTL_TEXTENCODING_MS_874 }, // ANSI/OEM Thai (ISO 8859-11); Thai (Windows)
+ { u"ja", RTL_TEXTENCODING_MS_932 }, // ANSI/OEM Japanese; Japanese (Shift-JIS)
+ { u"zh-cn", RTL_TEXTENCODING_MS_936 }, // ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
+ { u"ko", RTL_TEXTENCODING_MS_949 }, // ANSI/OEM Korean (Unified Hangul Code)
+ { u"zh", RTL_TEXTENCODING_MS_950 }, // ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)
+ { u"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: */