1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sax/tools/converter.hxx>
23 #include <xmloff/SettingsExportHelper.hxx>
24 #include <xmloff/xmltoken.hxx>
25 #include <rtl/ref.hxx>
26 #include <sal/log.hxx>
27 #include <tools/debug.hxx>
28 #include <comphelper/diagnose_ex.hxx>
29 #include <comphelper/base64.hxx>
30 #include <comphelper/extract.hxx>
32 #include <com/sun/star/linguistic2/XSupportedLocales.hpp>
33 #include <com/sun/star/i18n/XForbiddenCharacters.hpp>
34 #include <com/sun/star/beans/PropertyValue.hpp>
35 #include <com/sun/star/container/XNameAccess.hpp>
36 #include <com/sun/star/container/XNameContainer.hpp>
37 #include <com/sun/star/container/XIndexContainer.hpp>
38 #include <com/sun/star/util/PathSubstitution.hpp>
39 #include <com/sun/star/util/DateTime.hpp>
40 #include <com/sun/star/formula/SymbolDescriptor.hpp>
41 #include <com/sun/star/document/PrinterIndependentLayout.hpp>
42 #include <comphelper/indexedpropertyvalues.hxx>
43 #include <xmloff/XMLSettingsExportContext.hxx>
44 #include "xmlenums.hxx"
46 using namespace ::com::sun::star
;
47 using namespace ::xmloff::token
;
49 constexpr OUStringLiteral
gsPrinterIndependentLayout( u
"PrinterIndependentLayout" );
50 constexpr OUStringLiteral
gsColorTableURL( u
"ColorTableURL" );
51 constexpr OUStringLiteral
gsLineEndTableURL( u
"LineEndTableURL" );
52 constexpr OUStringLiteral
gsHatchTableURL( u
"HatchTableURL" );
53 constexpr OUStringLiteral
gsDashTableURL( u
"DashTableURL" );
54 constexpr OUStringLiteral
gsGradientTableURL( u
"GradientTableURL" );
55 constexpr OUStringLiteral
gsBitmapTableURL( u
"BitmapTableURL" );
57 XMLSettingsExportHelper::XMLSettingsExportHelper( ::xmloff::XMLSettingsExportContext
& i_rContext
)
58 : m_rContext( i_rContext
)
62 XMLSettingsExportHelper::~XMLSettingsExportHelper()
66 void XMLSettingsExportHelper::CallTypeFunction(const uno::Any
& rAny
,
67 const OUString
& rName
) const
69 uno::Any
aAny( rAny
);
70 ManipulateSetting( aAny
, rName
);
72 uno::TypeClass eClass
= aAny
.getValueTypeClass();
75 case uno::TypeClass_VOID
:
78 * This assertion pops up when exporting values which are set to:
79 * PropertyAttribute::MAYBEVOID, and thus are _supposed_ to have
80 * a VOID value...so I'm removing it ...mtg
81 * OSL_FAIL("no type");
85 case uno::TypeClass_BOOLEAN
:
87 exportBool(::cppu::any2bool(aAny
), rName
);
90 case uno::TypeClass_BYTE
:
95 case uno::TypeClass_SHORT
:
99 exportShort(nInt16
, rName
);
102 case uno::TypeClass_LONG
:
104 sal_Int32 nInt32
= 0;
106 exportInt(nInt32
, rName
);
109 case uno::TypeClass_HYPER
:
111 sal_Int64 nInt64
= 0;
113 exportLong(nInt64
, rName
);
116 case uno::TypeClass_DOUBLE
:
118 double fDouble
= 0.0;
120 exportDouble(fDouble
, rName
);
123 case uno::TypeClass_STRING
:
127 exportString(sString
, rName
);
132 const uno::Type
& aType
= aAny
.getValueType();
133 if (aType
.equals(cppu::UnoType
<uno::Sequence
<beans::PropertyValue
>>::get() ) )
135 uno::Sequence
< beans::PropertyValue
> aProps
;
137 exportSequencePropertyValue(aProps
, rName
);
139 else if( aType
.equals(cppu::UnoType
<uno::Sequence
<sal_Int8
>>::get() ) )
141 uno::Sequence
< sal_Int8
> aProps
;
143 exportbase64Binary(aProps
, rName
);
145 else if (aType
.equals(cppu::UnoType
<container::XNameContainer
>::get()) ||
146 aType
.equals(cppu::UnoType
<container::XNameAccess
>::get()))
148 uno::Reference
< container::XNameAccess
> aNamed
;
150 exportNameAccess(aNamed
, rName
);
152 else if (aType
.equals(cppu::UnoType
<container::XIndexAccess
>::get()) ||
153 aType
.equals(cppu::UnoType
<container::XIndexContainer
>::get()) )
155 uno::Reference
<container::XIndexAccess
> aIndexed
;
157 exportIndexAccess(aIndexed
, rName
);
159 else if (aType
.equals(cppu::UnoType
<util::DateTime
>::get()) )
161 util::DateTime aDateTime
;
163 exportDateTime(aDateTime
, rName
);
165 else if( aType
.equals(cppu::UnoType
<i18n::XForbiddenCharacters
>::get()) )
167 exportForbiddenCharacters( aAny
, rName
);
169 else if( aType
.equals(cppu::UnoType
<uno::Sequence
<formula::SymbolDescriptor
>>::get() ) )
171 uno::Sequence
< formula::SymbolDescriptor
> aProps
;
173 exportSymbolDescriptors(aProps
, rName
);
176 OSL_FAIL("this type is not implemented now");
183 void XMLSettingsExportHelper::exportBool(const bool bValue
, const OUString
& rName
) const
185 DBG_ASSERT(!rName
.isEmpty(), "no name");
186 m_rContext
.AddAttribute( XML_NAME
, rName
);
187 m_rContext
.AddAttribute( XML_TYPE
, XML_BOOLEAN
);
188 m_rContext
.StartElement( XML_CONFIG_ITEM
);
191 sValue
= GetXMLToken(XML_TRUE
);
193 sValue
= GetXMLToken(XML_FALSE
);
194 m_rContext
.Characters( sValue
);
195 m_rContext
.EndElement( false );
198 void XMLSettingsExportHelper::exportByte()
200 OSL_ENSURE(false, "XMLSettingsExportHelper::exportByte(): #i114162#:\n"
201 "config-items of type \"byte\" are not valid ODF, "
202 "so storing them is disabled!\n"
203 "Use a different type instead (e.g. \"short\").");
205 void XMLSettingsExportHelper::exportShort(const sal_Int16 nValue
, const OUString
& rName
) const
207 DBG_ASSERT(!rName
.isEmpty(), "no name");
208 m_rContext
.AddAttribute( XML_NAME
, rName
);
209 m_rContext
.AddAttribute( XML_TYPE
, XML_SHORT
);
210 m_rContext
.StartElement( XML_CONFIG_ITEM
);
211 m_rContext
.Characters( OUString::number(nValue
) );
212 m_rContext
.EndElement( false );
215 void XMLSettingsExportHelper::exportInt(const sal_Int32 nValue
, const OUString
& rName
) const
217 DBG_ASSERT(!rName
.isEmpty(), "no name");
218 m_rContext
.AddAttribute( XML_NAME
, rName
);
219 m_rContext
.AddAttribute( XML_TYPE
, XML_INT
);
220 m_rContext
.StartElement( XML_CONFIG_ITEM
);
221 m_rContext
.Characters( OUString::number(nValue
) );
222 m_rContext
.EndElement( false );
225 void XMLSettingsExportHelper::exportLong(const sal_Int64 nValue
, const OUString
& rName
) const
227 DBG_ASSERT(!rName
.isEmpty(), "no name");
228 m_rContext
.AddAttribute( XML_NAME
, rName
);
229 m_rContext
.AddAttribute( XML_TYPE
, XML_LONG
);
230 m_rContext
.StartElement( XML_CONFIG_ITEM
);
231 m_rContext
.Characters( OUString::number(nValue
) );
232 m_rContext
.EndElement( false );
235 void XMLSettingsExportHelper::exportDouble(const double fValue
, const OUString
& rName
) const
237 DBG_ASSERT(!rName
.isEmpty(), "no name");
238 m_rContext
.AddAttribute( XML_NAME
, rName
);
239 m_rContext
.AddAttribute( XML_TYPE
, XML_DOUBLE
);
240 m_rContext
.StartElement( XML_CONFIG_ITEM
);
241 OUStringBuffer sBuffer
;
242 ::sax::Converter::convertDouble(sBuffer
, fValue
);
243 m_rContext
.Characters( sBuffer
.makeStringAndClear() );
244 m_rContext
.EndElement( false );
247 void XMLSettingsExportHelper::exportString(const OUString
& sValue
, const OUString
& rName
) const
249 DBG_ASSERT(!rName
.isEmpty(), "no name");
250 m_rContext
.AddAttribute( XML_NAME
, rName
);
251 m_rContext
.AddAttribute( XML_TYPE
, XML_STRING
);
252 m_rContext
.StartElement( XML_CONFIG_ITEM
);
253 if (!sValue
.isEmpty())
254 m_rContext
.Characters( sValue
);
255 m_rContext
.EndElement( false );
258 void XMLSettingsExportHelper::exportDateTime(const util::DateTime
& aValue
, const OUString
& rName
) const
260 DBG_ASSERT(!rName
.isEmpty(), "no name");
261 m_rContext
.AddAttribute( XML_NAME
, rName
);
262 m_rContext
.AddAttribute( XML_TYPE
, XML_DATETIME
);
263 OUStringBuffer sBuffer
;
264 ::sax::Converter::convertDateTime(sBuffer
, aValue
, nullptr);
265 m_rContext
.StartElement( XML_CONFIG_ITEM
);
266 m_rContext
.Characters( sBuffer
.makeStringAndClear() );
267 m_rContext
.EndElement( false );
270 void XMLSettingsExportHelper::exportSequencePropertyValue(
271 const uno::Sequence
<beans::PropertyValue
>& aProps
,
272 const OUString
& rName
) const
274 DBG_ASSERT(!rName
.isEmpty(), "no name");
275 if(aProps
.hasElements())
277 m_rContext
.AddAttribute( XML_NAME
, rName
);
278 m_rContext
.StartElement( XML_CONFIG_ITEM_SET
);
279 for (const auto& rProp
: aProps
)
280 CallTypeFunction(rProp
.Value
, rProp
.Name
);
281 m_rContext
.EndElement( true );
284 void XMLSettingsExportHelper::exportSymbolDescriptors(
285 const uno::Sequence
< formula::SymbolDescriptor
> &rProps
,
286 const OUString
& rName
) const
288 rtl::Reference
< comphelper::IndexedPropertyValuesContainer
> xBox
= new comphelper::IndexedPropertyValuesContainer();
290 static constexpr OUStringLiteral
sName ( u
"Name" );
291 static constexpr OUStringLiteral
sExportName ( u
"ExportName" );
292 static constexpr OUStringLiteral
sSymbolSet ( u
"SymbolSet" );
293 static constexpr OUStringLiteral
sCharacter ( u
"Character" );
294 static constexpr OUStringLiteral
sFontName ( u
"FontName" );
295 static constexpr OUStringLiteral
sCharSet ( u
"CharSet" );
296 static constexpr OUStringLiteral
sFamily ( u
"Family" );
297 static constexpr OUStringLiteral
sPitch ( u
"Pitch" );
298 static constexpr OUStringLiteral
sWeight ( u
"Weight" );
299 static constexpr OUStringLiteral
sItalic ( u
"Italic" );
301 sal_Int32 nCount
= rProps
.getLength();
302 const formula::SymbolDescriptor
*pDescriptor
= rProps
.getConstArray();
304 for( sal_Int32 nIndex
= 0; nIndex
< nCount
; nIndex
++, pDescriptor
++ )
306 uno::Sequence
< beans::PropertyValue
> aSequence ( XML_SYMBOL_DESCRIPTOR_MAX
);
307 beans::PropertyValue
*pSymbol
= aSequence
.getArray();
309 pSymbol
[XML_SYMBOL_DESCRIPTOR_NAME
].Name
= sName
;
310 pSymbol
[XML_SYMBOL_DESCRIPTOR_NAME
].Value
<<= pDescriptor
->sName
;
311 pSymbol
[XML_SYMBOL_DESCRIPTOR_EXPORT_NAME
].Name
= sExportName
;
312 pSymbol
[XML_SYMBOL_DESCRIPTOR_EXPORT_NAME
].Value
<<= pDescriptor
->sExportName
;
313 pSymbol
[XML_SYMBOL_DESCRIPTOR_FONT_NAME
].Name
= sFontName
;
314 pSymbol
[XML_SYMBOL_DESCRIPTOR_FONT_NAME
].Value
<<= pDescriptor
->sFontName
;
315 pSymbol
[XML_SYMBOL_DESCRIPTOR_CHAR_SET
].Name
= sCharSet
;
316 pSymbol
[XML_SYMBOL_DESCRIPTOR_CHAR_SET
].Value
<<= pDescriptor
->nCharSet
;
317 pSymbol
[XML_SYMBOL_DESCRIPTOR_FAMILY
].Name
= sFamily
;
318 pSymbol
[XML_SYMBOL_DESCRIPTOR_FAMILY
].Value
<<= pDescriptor
->nFamily
;
319 pSymbol
[XML_SYMBOL_DESCRIPTOR_PITCH
].Name
= sPitch
;
320 pSymbol
[XML_SYMBOL_DESCRIPTOR_PITCH
].Value
<<= pDescriptor
->nPitch
;
321 pSymbol
[XML_SYMBOL_DESCRIPTOR_WEIGHT
].Name
= sWeight
;
322 pSymbol
[XML_SYMBOL_DESCRIPTOR_WEIGHT
].Value
<<= pDescriptor
->nWeight
;
323 pSymbol
[XML_SYMBOL_DESCRIPTOR_ITALIC
].Name
= sItalic
;
324 pSymbol
[XML_SYMBOL_DESCRIPTOR_ITALIC
].Value
<<= pDescriptor
->nItalic
;
325 pSymbol
[XML_SYMBOL_DESCRIPTOR_SYMBOL_SET
].Name
= sSymbolSet
;
326 pSymbol
[XML_SYMBOL_DESCRIPTOR_SYMBOL_SET
].Value
<<= pDescriptor
->sSymbolSet
;
327 pSymbol
[XML_SYMBOL_DESCRIPTOR_CHARACTER
].Name
= sCharacter
;
328 pSymbol
[XML_SYMBOL_DESCRIPTOR_CHARACTER
].Value
<<= pDescriptor
->nCharacter
;
330 xBox
->insertByIndex(nIndex
, uno::Any( aSequence
));
333 exportIndexAccess( xBox
, rName
);
335 void XMLSettingsExportHelper::exportbase64Binary(
336 const uno::Sequence
<sal_Int8
>& aProps
,
337 const OUString
& rName
) const
339 DBG_ASSERT(!rName
.isEmpty(), "no name");
340 m_rContext
.AddAttribute( XML_NAME
, rName
);
341 m_rContext
.AddAttribute( XML_TYPE
, XML_BASE64BINARY
);
342 m_rContext
.StartElement( XML_CONFIG_ITEM
);
343 if(aProps
.hasElements())
345 OUStringBuffer sBuffer
;
346 ::comphelper::Base64::encode(sBuffer
, aProps
);
347 m_rContext
.Characters( sBuffer
.makeStringAndClear() );
349 m_rContext
.EndElement( false );
352 void XMLSettingsExportHelper::exportMapEntry(const uno::Any
& rAny
,
353 const OUString
& rName
,
354 const bool bNameAccess
) const
356 DBG_ASSERT((bNameAccess
&& !rName
.isEmpty()) || !bNameAccess
, "no name");
357 uno::Sequence
<beans::PropertyValue
> aProps
;
359 if (aProps
.hasElements())
362 m_rContext
.AddAttribute( XML_NAME
, rName
);
363 m_rContext
.StartElement( XML_CONFIG_ITEM_MAP_ENTRY
);
364 for (const auto& rProp
: std::as_const(aProps
))
365 CallTypeFunction(rProp
.Value
, rProp
.Name
);
366 m_rContext
.EndElement( true );
370 void XMLSettingsExportHelper::exportNameAccess(
371 const uno::Reference
<container::XNameAccess
>& aNamed
,
372 const OUString
& rName
) const
374 DBG_ASSERT(!rName
.isEmpty(), "no name");
375 DBG_ASSERT(aNamed
->getElementType().equals(cppu::UnoType
<uno::Sequence
<beans::PropertyValue
>>::get() ),
376 "wrong NameAccess" );
377 if(aNamed
->hasElements())
379 m_rContext
.AddAttribute( XML_NAME
, rName
);
380 m_rContext
.StartElement( XML_CONFIG_ITEM_MAP_NAMED
);
381 const uno::Sequence
< OUString
> aNames(aNamed
->getElementNames());
382 for (const auto& rElementName
: aNames
)
383 exportMapEntry(aNamed
->getByName(rElementName
), rElementName
, true);
384 m_rContext
.EndElement( true );
388 void XMLSettingsExportHelper::exportIndexAccess(
389 const uno::Reference
<container::XIndexAccess
>& rIndexed
,
390 const OUString
& rName
) const
392 DBG_ASSERT(!rName
.isEmpty(), "no name");
393 DBG_ASSERT(rIndexed
->getElementType().equals(cppu::UnoType
<uno::Sequence
<beans::PropertyValue
>>::get() ),
394 "wrong IndexAccess" );
395 if (rIndexed
->hasElements())
397 m_rContext
.AddAttribute( XML_NAME
, rName
);
398 m_rContext
.StartElement( XML_CONFIG_ITEM_MAP_INDEXED
);
399 sal_Int32 nCount
= rIndexed
->getCount();
400 for (sal_Int32 i
= 0; i
< nCount
; i
++)
402 exportMapEntry(rIndexed
->getByIndex(i
), "", false);
404 m_rContext
.EndElement( true );
408 void XMLSettingsExportHelper::exportForbiddenCharacters(
409 const uno::Any
&rAny
,
410 const OUString
& rName
) const
412 uno::Reference
<i18n::XForbiddenCharacters
> xForbChars
;
413 uno::Reference
<linguistic2::XSupportedLocales
> xLocales
;
418 SAL_WARN_IF( !(xForbChars
.is() && xLocales
.is()), "xmloff","XMLSettingsExportHelper::exportForbiddenCharacters: got illegal forbidden characters!" );
420 if( !xForbChars
.is() || !xLocales
.is() )
423 rtl::Reference
< comphelper::IndexedPropertyValuesContainer
> xBox
= new comphelper::IndexedPropertyValuesContainer();
424 const uno::Sequence
< lang::Locale
> aLocales( xLocales
->getLocales() );
426 /* FIXME-BCP47: this stupid and counterpart in
427 * xmloff/source/core/DocumentSettingsContext.cxx
428 * XMLConfigItemMapIndexedContext::EndElement() */
430 static constexpr OUStringLiteral
sLanguage ( u
"Language" );
431 static constexpr OUStringLiteral
sCountry ( u
"Country" );
432 static constexpr OUStringLiteral
sVariant ( u
"Variant" );
433 static constexpr OUStringLiteral
sBeginLine ( u
"BeginLine" );
434 static constexpr OUStringLiteral
sEndLine ( u
"EndLine" );
437 for( const auto& rLocale
: aLocales
)
439 if( xForbChars
->hasForbiddenCharacters( rLocale
) )
441 const i18n::ForbiddenCharacters
aChars( xForbChars
->getForbiddenCharacters( rLocale
) );
444 uno::Sequence
< beans::PropertyValue
> aSequence ( XML_FORBIDDEN_CHARACTER_MAX
);
445 beans::PropertyValue
*pForChar
= aSequence
.getArray();
447 pForChar
[XML_FORBIDDEN_CHARACTER_LANGUAGE
].Name
= sLanguage
;
448 pForChar
[XML_FORBIDDEN_CHARACTER_LANGUAGE
].Value
<<= rLocale
.Language
;
449 pForChar
[XML_FORBIDDEN_CHARACTER_COUNTRY
].Name
= sCountry
;
450 pForChar
[XML_FORBIDDEN_CHARACTER_COUNTRY
].Value
<<= rLocale
.Country
;
451 pForChar
[XML_FORBIDDEN_CHARACTER_VARIANT
].Name
= sVariant
;
452 pForChar
[XML_FORBIDDEN_CHARACTER_VARIANT
].Value
<<= rLocale
.Variant
;
453 pForChar
[XML_FORBIDDEN_CHARACTER_BEGIN_LINE
].Name
= sBeginLine
;
454 pForChar
[XML_FORBIDDEN_CHARACTER_BEGIN_LINE
].Value
<<= aChars
.beginLine
;
455 pForChar
[XML_FORBIDDEN_CHARACTER_END_LINE
].Name
= sEndLine
;
456 pForChar
[XML_FORBIDDEN_CHARACTER_END_LINE
].Value
<<= aChars
.endLine
;
457 xBox
->insertByIndex(nPos
++, uno::Any( aSequence
));
461 exportIndexAccess( xBox
, rName
);
464 void XMLSettingsExportHelper::exportAllSettings(
465 const uno::Sequence
<beans::PropertyValue
>& aProps
,
466 const OUString
& rName
) const
468 DBG_ASSERT(!rName
.isEmpty(), "no name");
469 exportSequencePropertyValue(aProps
, rName
);
473 /** For some settings we may want to change their API representation
474 * from their XML settings representation. This is your chance to do
477 void XMLSettingsExportHelper::ManipulateSetting( uno::Any
& rAny
, std::u16string_view rName
) const
479 if( rName
== gsPrinterIndependentLayout
)
481 sal_Int16 nTmp
= sal_Int16();
484 if( nTmp
== document::PrinterIndependentLayout::LOW_RESOLUTION
)
485 rAny
<<= OUString("low-resolution");
486 else if( nTmp
== document::PrinterIndependentLayout::DISABLED
)
487 rAny
<<= OUString("disabled");
488 else if( nTmp
== document::PrinterIndependentLayout::HIGH_RESOLUTION
)
489 rAny
<<= OUString("high-resolution");
492 else if( (rName
== gsColorTableURL
) || (rName
== gsLineEndTableURL
) || (rName
== gsHatchTableURL
) ||
493 (rName
== gsDashTableURL
) || (rName
== gsGradientTableURL
) || (rName
== gsBitmapTableURL
) )
495 if( !mxStringSubstitution
.is() )
499 const_cast< XMLSettingsExportHelper
* >(this)->mxStringSubstitution
=
500 util::PathSubstitution::create( m_rContext
.GetComponentContext() );
502 catch( uno::Exception
& )
504 DBG_UNHANDLED_EXCEPTION("xmloff.core");
508 if( mxStringSubstitution
.is() )
512 aURL
= mxStringSubstitution
->reSubstituteVariables( aURL
);
518 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */