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>
31 #include <unotools/securityoptions.hxx>
33 #include <com/sun/star/linguistic2/XSupportedLocales.hpp>
34 #include <com/sun/star/i18n/XForbiddenCharacters.hpp>
35 #include <com/sun/star/beans/PropertyValue.hpp>
36 #include <com/sun/star/container/XNameAccess.hpp>
37 #include <com/sun/star/container/XNameContainer.hpp>
38 #include <com/sun/star/container/XIndexContainer.hpp>
39 #include <com/sun/star/util/PathSubstitution.hpp>
40 #include <com/sun/star/util/DateTime.hpp>
41 #include <com/sun/star/formula/SymbolDescriptor.hpp>
42 #include <com/sun/star/document/PrinterIndependentLayout.hpp>
43 #include <comphelper/indexedpropertyvalues.hxx>
44 #include <xmloff/XMLSettingsExportContext.hxx>
45 #include "xmlenums.hxx"
47 using namespace ::com::sun::star
;
48 using namespace ::xmloff::token
;
50 constexpr OUStringLiteral
gsPrinterIndependentLayout( u
"PrinterIndependentLayout" );
51 constexpr OUStringLiteral
gsColorTableURL( u
"ColorTableURL" );
52 constexpr OUStringLiteral
gsLineEndTableURL( u
"LineEndTableURL" );
53 constexpr OUStringLiteral
gsHatchTableURL( u
"HatchTableURL" );
54 constexpr OUStringLiteral
gsDashTableURL( u
"DashTableURL" );
55 constexpr OUStringLiteral
gsGradientTableURL( u
"GradientTableURL" );
56 constexpr OUStringLiteral
gsBitmapTableURL( u
"BitmapTableURL" );
58 XMLSettingsExportHelper::XMLSettingsExportHelper( ::xmloff::XMLSettingsExportContext
& i_rContext
)
59 : m_rContext( i_rContext
)
63 XMLSettingsExportHelper::~XMLSettingsExportHelper()
67 void XMLSettingsExportHelper::CallTypeFunction(const uno::Any
& rAny
,
68 const OUString
& rName
) const
70 uno::Any
aAny( rAny
);
71 ManipulateSetting( aAny
, rName
);
73 uno::TypeClass eClass
= aAny
.getValueTypeClass();
76 case uno::TypeClass_VOID
:
79 * This assertion pops up when exporting values which are set to:
80 * PropertyAttribute::MAYBEVOID, and thus are _supposed_ to have
81 * a VOID value...so I'm removing it ...mtg
82 * OSL_FAIL("no type");
86 case uno::TypeClass_BOOLEAN
:
88 exportBool(::cppu::any2bool(aAny
), rName
);
91 case uno::TypeClass_BYTE
:
96 case uno::TypeClass_SHORT
:
100 exportShort(nInt16
, rName
);
103 case uno::TypeClass_LONG
:
105 sal_Int32 nInt32
= 0;
107 exportInt(nInt32
, rName
);
110 case uno::TypeClass_HYPER
:
112 sal_Int64 nInt64
= 0;
114 exportLong(nInt64
, rName
);
117 case uno::TypeClass_DOUBLE
:
119 double fDouble
= 0.0;
121 exportDouble(fDouble
, rName
);
124 case uno::TypeClass_STRING
:
128 exportString(sString
, rName
);
133 const uno::Type
& aType
= aAny
.getValueType();
134 if (aType
.equals(cppu::UnoType
<uno::Sequence
<beans::PropertyValue
>>::get() ) )
136 uno::Sequence
< beans::PropertyValue
> aProps
;
138 exportSequencePropertyValue(aProps
, rName
);
140 else if( aType
.equals(cppu::UnoType
<uno::Sequence
<sal_Int8
>>::get() ) )
142 uno::Sequence
< sal_Int8
> aProps
;
144 exportbase64Binary(aProps
, rName
);
146 else if (uno::Reference
<container::XNameAccess
> aNamed
; aAny
>>= aNamed
)
148 exportNameAccess(aNamed
, rName
);
150 else if (uno::Reference
<container::XIndexAccess
> aIndexed
; aAny
>>= aIndexed
)
152 exportIndexAccess(aIndexed
, rName
);
154 else if (aType
.equals(cppu::UnoType
<util::DateTime
>::get()) )
156 util::DateTime aDateTime
;
158 exportDateTime(aDateTime
, rName
);
160 else if (uno::Reference
<i18n::XForbiddenCharacters
> xForbChars
; aAny
>>= xForbChars
)
162 exportForbiddenCharacters(xForbChars
, rName
);
164 else if( aType
.equals(cppu::UnoType
<uno::Sequence
<formula::SymbolDescriptor
>>::get() ) )
166 uno::Sequence
< formula::SymbolDescriptor
> aProps
;
168 exportSymbolDescriptors(aProps
, rName
);
171 OSL_FAIL("this type is not implemented now");
178 void XMLSettingsExportHelper::exportBool(const bool bValue
, const OUString
& rName
) const
180 DBG_ASSERT(!rName
.isEmpty(), "no name");
181 m_rContext
.AddAttribute( XML_NAME
, rName
);
182 m_rContext
.AddAttribute( XML_TYPE
, XML_BOOLEAN
);
183 m_rContext
.StartElement( XML_CONFIG_ITEM
);
186 sValue
= GetXMLToken(XML_TRUE
);
188 sValue
= GetXMLToken(XML_FALSE
);
189 m_rContext
.Characters( sValue
);
190 m_rContext
.EndElement( false );
193 void XMLSettingsExportHelper::exportByte()
195 OSL_ENSURE(false, "XMLSettingsExportHelper::exportByte(): #i114162#:\n"
196 "config-items of type \"byte\" are not valid ODF, "
197 "so storing them is disabled!\n"
198 "Use a different type instead (e.g. \"short\").");
200 void XMLSettingsExportHelper::exportShort(const sal_Int16 nValue
, const OUString
& rName
) const
202 DBG_ASSERT(!rName
.isEmpty(), "no name");
203 m_rContext
.AddAttribute( XML_NAME
, rName
);
204 m_rContext
.AddAttribute( XML_TYPE
, XML_SHORT
);
205 m_rContext
.StartElement( XML_CONFIG_ITEM
);
206 m_rContext
.Characters( OUString::number(nValue
) );
207 m_rContext
.EndElement( false );
210 void XMLSettingsExportHelper::exportInt(const sal_Int32 nValue
, const OUString
& rName
) const
212 DBG_ASSERT(!rName
.isEmpty(), "no name");
213 m_rContext
.AddAttribute( XML_NAME
, rName
);
214 m_rContext
.AddAttribute( XML_TYPE
, XML_INT
);
215 m_rContext
.StartElement( XML_CONFIG_ITEM
);
216 m_rContext
.Characters( OUString::number(nValue
) );
217 m_rContext
.EndElement( false );
220 void XMLSettingsExportHelper::exportLong(const sal_Int64 nValue
, const OUString
& rName
) const
222 DBG_ASSERT(!rName
.isEmpty(), "no name");
223 m_rContext
.AddAttribute( XML_NAME
, rName
);
224 m_rContext
.AddAttribute( XML_TYPE
, XML_LONG
);
225 m_rContext
.StartElement( XML_CONFIG_ITEM
);
226 m_rContext
.Characters( OUString::number(nValue
) );
227 m_rContext
.EndElement( false );
230 void XMLSettingsExportHelper::exportDouble(const double fValue
, const OUString
& rName
) const
232 DBG_ASSERT(!rName
.isEmpty(), "no name");
233 m_rContext
.AddAttribute( XML_NAME
, rName
);
234 m_rContext
.AddAttribute( XML_TYPE
, XML_DOUBLE
);
235 m_rContext
.StartElement( XML_CONFIG_ITEM
);
236 OUStringBuffer sBuffer
;
237 ::sax::Converter::convertDouble(sBuffer
, fValue
);
238 m_rContext
.Characters( sBuffer
.makeStringAndClear() );
239 m_rContext
.EndElement( false );
242 void XMLSettingsExportHelper::exportString(const OUString
& sValue
, const OUString
& rName
) const
244 DBG_ASSERT(!rName
.isEmpty(), "no name");
245 m_rContext
.AddAttribute( XML_NAME
, rName
);
246 m_rContext
.AddAttribute( XML_TYPE
, XML_STRING
);
247 m_rContext
.StartElement( XML_CONFIG_ITEM
);
248 if (!sValue
.isEmpty())
249 m_rContext
.Characters( sValue
);
250 m_rContext
.EndElement( false );
253 void XMLSettingsExportHelper::exportDateTime(const util::DateTime
& aValue
, const OUString
& rName
) const
255 DBG_ASSERT(!rName
.isEmpty(), "no name");
256 m_rContext
.AddAttribute( XML_NAME
, rName
);
257 m_rContext
.AddAttribute( XML_TYPE
, XML_DATETIME
);
258 OUStringBuffer sBuffer
;
259 ::sax::Converter::convertDateTime(sBuffer
, aValue
, nullptr);
260 m_rContext
.StartElement( XML_CONFIG_ITEM
);
261 m_rContext
.Characters( sBuffer
.makeStringAndClear() );
262 m_rContext
.EndElement( false );
265 void XMLSettingsExportHelper::exportSequencePropertyValue(
266 const uno::Sequence
<beans::PropertyValue
>& aProps
,
267 const OUString
& rName
) const
269 DBG_ASSERT(!rName
.isEmpty(), "no name");
270 if(aProps
.hasElements())
272 m_rContext
.AddAttribute( XML_NAME
, rName
);
273 m_rContext
.StartElement( XML_CONFIG_ITEM_SET
);
274 bool bSkipPrinterSettings
= SvtSecurityOptions::IsOptionSet(
275 SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo
)
276 && !SvtSecurityOptions::IsOptionSet(
277 SvtSecurityOptions::EOption::DocKeepPrinterSettings
);
278 for (const auto& rProp
: aProps
)
280 if (bSkipPrinterSettings
281 && (rProp
.Name
== "PrinterSetup" || rProp
.Name
== "PrinterName"))
283 CallTypeFunction(rProp
.Value
, rProp
.Name
);
285 m_rContext
.EndElement( true );
288 void XMLSettingsExportHelper::exportSymbolDescriptors(
289 const uno::Sequence
< formula::SymbolDescriptor
> &rProps
,
290 const OUString
& rName
) const
292 rtl::Reference
< comphelper::IndexedPropertyValuesContainer
> xBox
= new comphelper::IndexedPropertyValuesContainer();
294 static constexpr OUStringLiteral
sName ( u
"Name" );
295 static constexpr OUStringLiteral
sExportName ( u
"ExportName" );
296 static constexpr OUStringLiteral
sSymbolSet ( u
"SymbolSet" );
297 static constexpr OUStringLiteral
sCharacter ( u
"Character" );
298 static constexpr OUStringLiteral
sFontName ( u
"FontName" );
299 static constexpr OUStringLiteral
sCharSet ( u
"CharSet" );
300 static constexpr OUStringLiteral
sFamily ( u
"Family" );
301 static constexpr OUStringLiteral
sPitch ( u
"Pitch" );
302 static constexpr OUStringLiteral
sWeight ( u
"Weight" );
303 static constexpr OUStringLiteral
sItalic ( u
"Italic" );
305 sal_Int32 nCount
= rProps
.getLength();
306 const formula::SymbolDescriptor
*pDescriptor
= rProps
.getConstArray();
308 for( sal_Int32 nIndex
= 0; nIndex
< nCount
; nIndex
++, pDescriptor
++ )
310 uno::Sequence
< beans::PropertyValue
> aSequence ( XML_SYMBOL_DESCRIPTOR_MAX
);
311 beans::PropertyValue
*pSymbol
= aSequence
.getArray();
313 pSymbol
[XML_SYMBOL_DESCRIPTOR_NAME
].Name
= sName
;
314 pSymbol
[XML_SYMBOL_DESCRIPTOR_NAME
].Value
<<= pDescriptor
->sName
;
315 pSymbol
[XML_SYMBOL_DESCRIPTOR_EXPORT_NAME
].Name
= sExportName
;
316 pSymbol
[XML_SYMBOL_DESCRIPTOR_EXPORT_NAME
].Value
<<= pDescriptor
->sExportName
;
317 pSymbol
[XML_SYMBOL_DESCRIPTOR_FONT_NAME
].Name
= sFontName
;
318 pSymbol
[XML_SYMBOL_DESCRIPTOR_FONT_NAME
].Value
<<= pDescriptor
->sFontName
;
319 pSymbol
[XML_SYMBOL_DESCRIPTOR_CHAR_SET
].Name
= sCharSet
;
320 pSymbol
[XML_SYMBOL_DESCRIPTOR_CHAR_SET
].Value
<<= pDescriptor
->nCharSet
;
321 pSymbol
[XML_SYMBOL_DESCRIPTOR_FAMILY
].Name
= sFamily
;
322 pSymbol
[XML_SYMBOL_DESCRIPTOR_FAMILY
].Value
<<= pDescriptor
->nFamily
;
323 pSymbol
[XML_SYMBOL_DESCRIPTOR_PITCH
].Name
= sPitch
;
324 pSymbol
[XML_SYMBOL_DESCRIPTOR_PITCH
].Value
<<= pDescriptor
->nPitch
;
325 pSymbol
[XML_SYMBOL_DESCRIPTOR_WEIGHT
].Name
= sWeight
;
326 pSymbol
[XML_SYMBOL_DESCRIPTOR_WEIGHT
].Value
<<= pDescriptor
->nWeight
;
327 pSymbol
[XML_SYMBOL_DESCRIPTOR_ITALIC
].Name
= sItalic
;
328 pSymbol
[XML_SYMBOL_DESCRIPTOR_ITALIC
].Value
<<= pDescriptor
->nItalic
;
329 pSymbol
[XML_SYMBOL_DESCRIPTOR_SYMBOL_SET
].Name
= sSymbolSet
;
330 pSymbol
[XML_SYMBOL_DESCRIPTOR_SYMBOL_SET
].Value
<<= pDescriptor
->sSymbolSet
;
331 pSymbol
[XML_SYMBOL_DESCRIPTOR_CHARACTER
].Name
= sCharacter
;
332 pSymbol
[XML_SYMBOL_DESCRIPTOR_CHARACTER
].Value
<<= pDescriptor
->nCharacter
;
334 xBox
->insertByIndex(nIndex
, uno::Any( aSequence
));
337 exportIndexAccess( xBox
, rName
);
339 void XMLSettingsExportHelper::exportbase64Binary(
340 const uno::Sequence
<sal_Int8
>& aProps
,
341 const OUString
& rName
) const
343 DBG_ASSERT(!rName
.isEmpty(), "no name");
344 m_rContext
.AddAttribute( XML_NAME
, rName
);
345 m_rContext
.AddAttribute( XML_TYPE
, XML_BASE64BINARY
);
346 m_rContext
.StartElement( XML_CONFIG_ITEM
);
347 if(aProps
.hasElements())
349 OUStringBuffer sBuffer
;
350 ::comphelper::Base64::encode(sBuffer
, aProps
);
351 m_rContext
.Characters( sBuffer
.makeStringAndClear() );
353 m_rContext
.EndElement( false );
356 void XMLSettingsExportHelper::exportMapEntry(const uno::Any
& rAny
,
357 const OUString
& rName
,
358 const bool bNameAccess
) const
360 DBG_ASSERT((bNameAccess
&& !rName
.isEmpty()) || !bNameAccess
, "no name");
361 uno::Sequence
<beans::PropertyValue
> aProps
;
363 if (aProps
.hasElements())
366 m_rContext
.AddAttribute( XML_NAME
, rName
);
367 m_rContext
.StartElement( XML_CONFIG_ITEM_MAP_ENTRY
);
368 for (const auto& rProp
: aProps
)
369 CallTypeFunction(rProp
.Value
, rProp
.Name
);
370 m_rContext
.EndElement( true );
374 void XMLSettingsExportHelper::exportNameAccess(
375 const uno::Reference
<container::XNameAccess
>& aNamed
,
376 const OUString
& rName
) const
378 DBG_ASSERT(!rName
.isEmpty(), "no name");
379 DBG_ASSERT(aNamed
->getElementType().equals(cppu::UnoType
<uno::Sequence
<beans::PropertyValue
>>::get() ),
380 "wrong NameAccess" );
381 if(aNamed
->hasElements())
383 m_rContext
.AddAttribute( XML_NAME
, rName
);
384 m_rContext
.StartElement( XML_CONFIG_ITEM_MAP_NAMED
);
385 const uno::Sequence
< OUString
> aNames(aNamed
->getElementNames());
386 for (const auto& rElementName
: aNames
)
387 exportMapEntry(aNamed
->getByName(rElementName
), rElementName
, true);
388 m_rContext
.EndElement( true );
392 void XMLSettingsExportHelper::exportIndexAccess(
393 const uno::Reference
<container::XIndexAccess
>& rIndexed
,
394 const OUString
& rName
) const
396 DBG_ASSERT(!rName
.isEmpty(), "no name");
397 DBG_ASSERT(rIndexed
->getElementType().equals(cppu::UnoType
<uno::Sequence
<beans::PropertyValue
>>::get() ),
398 "wrong IndexAccess" );
399 if (rIndexed
->hasElements())
401 m_rContext
.AddAttribute( XML_NAME
, rName
);
402 m_rContext
.StartElement( XML_CONFIG_ITEM_MAP_INDEXED
);
403 sal_Int32 nCount
= rIndexed
->getCount();
404 for (sal_Int32 i
= 0; i
< nCount
; i
++)
406 exportMapEntry(rIndexed
->getByIndex(i
), u
""_ustr
, false);
408 m_rContext
.EndElement( true );
412 void XMLSettingsExportHelper::exportForbiddenCharacters(
413 const uno::Reference
<i18n::XForbiddenCharacters
>& xForbChars
,
414 const OUString
& rName
) const
416 uno::Reference
<linguistic2::XSupportedLocales
> xLocales(xForbChars
, css::uno::UNO_QUERY
);
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
<<= u
"low-resolution"_ustr
;
486 else if( nTmp
== document::PrinterIndependentLayout::DISABLED
)
487 rAny
<<= u
"disabled"_ustr
;
488 else if( nTmp
== document::PrinterIndependentLayout::HIGH_RESOLUTION
)
489 rAny
<<= u
"high-resolution"_ustr
;
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: */