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 <sal/log.hxx>
26 #include <tools/debug.hxx>
27 #include <tools/diagnose_ex.h>
28 #include <comphelper/base64.hxx>
29 #include <comphelper/extract.hxx>
31 #include <com/sun/star/linguistic2/XSupportedLocales.hpp>
32 #include <com/sun/star/i18n/XForbiddenCharacters.hpp>
33 #include <com/sun/star/beans/PropertyValue.hpp>
34 #include <com/sun/star/container/XNameAccess.hpp>
35 #include <com/sun/star/container/XNameContainer.hpp>
36 #include <com/sun/star/container/XIndexContainer.hpp>
37 #include <com/sun/star/util/PathSubstitution.hpp>
38 #include <com/sun/star/util/DateTime.hpp>
39 #include <com/sun/star/formula/SymbolDescriptor.hpp>
40 #include <com/sun/star/document/PrinterIndependentLayout.hpp>
41 #include <com/sun/star/document/IndexedPropertyValues.hpp>
42 #include <xmloff/XMLSettingsExportContext.hxx>
43 #include "xmlenums.hxx"
45 using namespace ::com::sun::star
;
46 using namespace ::xmloff::token
;
48 constexpr OUStringLiteral
gsPrinterIndependentLayout( u
"PrinterIndependentLayout" );
49 constexpr OUStringLiteral
gsColorTableURL( u
"ColorTableURL" );
50 constexpr OUStringLiteral
gsLineEndTableURL( u
"LineEndTableURL" );
51 constexpr OUStringLiteral
gsHatchTableURL( u
"HatchTableURL" );
52 constexpr OUStringLiteral
gsDashTableURL( u
"DashTableURL" );
53 constexpr OUStringLiteral
gsGradientTableURL( u
"GradientTableURL" );
54 constexpr OUStringLiteral
gsBitmapTableURL( u
"BitmapTableURL" );
56 XMLSettingsExportHelper::XMLSettingsExportHelper( ::xmloff::XMLSettingsExportContext
& i_rContext
)
57 : m_rContext( i_rContext
)
61 XMLSettingsExportHelper::~XMLSettingsExportHelper()
65 void XMLSettingsExportHelper::CallTypeFunction(const uno::Any
& rAny
,
66 const OUString
& rName
) const
68 uno::Any
aAny( rAny
);
69 ManipulateSetting( aAny
, rName
);
71 uno::TypeClass eClass
= aAny
.getValueTypeClass();
74 case uno::TypeClass_VOID
:
77 * This assertion pops up when exporting values which are set to:
78 * PropertyAttribute::MAYBEVOID, and thus are _supposed_ to have
79 * a VOID value...so I'm removing it ...mtg
80 * OSL_FAIL("no type");
84 case uno::TypeClass_BOOLEAN
:
86 exportBool(::cppu::any2bool(aAny
), rName
);
89 case uno::TypeClass_BYTE
:
94 case uno::TypeClass_SHORT
:
98 exportShort(nInt16
, rName
);
101 case uno::TypeClass_LONG
:
103 sal_Int32 nInt32
= 0;
105 exportInt(nInt32
, rName
);
108 case uno::TypeClass_HYPER
:
110 sal_Int64 nInt64
= 0;
112 exportLong(nInt64
, rName
);
115 case uno::TypeClass_DOUBLE
:
117 double fDouble
= 0.0;
119 exportDouble(fDouble
, rName
);
122 case uno::TypeClass_STRING
:
126 exportString(sString
, rName
);
131 const uno::Type
& aType
= aAny
.getValueType();
132 if (aType
.equals(cppu::UnoType
<uno::Sequence
<beans::PropertyValue
>>::get() ) )
134 uno::Sequence
< beans::PropertyValue
> aProps
;
136 exportSequencePropertyValue(aProps
, rName
);
138 else if( aType
.equals(cppu::UnoType
<uno::Sequence
<sal_Int8
>>::get() ) )
140 uno::Sequence
< sal_Int8
> aProps
;
142 exportbase64Binary(aProps
, rName
);
144 else if (aType
.equals(cppu::UnoType
<container::XNameContainer
>::get()) ||
145 aType
.equals(cppu::UnoType
<container::XNameAccess
>::get()))
147 uno::Reference
< container::XNameAccess
> aNamed
;
149 exportNameAccess(aNamed
, rName
);
151 else if (aType
.equals(cppu::UnoType
<container::XIndexAccess
>::get()) ||
152 aType
.equals(cppu::UnoType
<container::XIndexContainer
>::get()) )
154 uno::Reference
<container::XIndexAccess
> aIndexed
;
156 exportIndexAccess(aIndexed
, rName
);
158 else if (aType
.equals(cppu::UnoType
<util::DateTime
>::get()) )
160 util::DateTime aDateTime
;
162 exportDateTime(aDateTime
, rName
);
164 else if( aType
.equals(cppu::UnoType
<i18n::XForbiddenCharacters
>::get()) )
166 exportForbiddenCharacters( aAny
, rName
);
168 else if( aType
.equals(cppu::UnoType
<uno::Sequence
<formula::SymbolDescriptor
>>::get() ) )
170 uno::Sequence
< formula::SymbolDescriptor
> aProps
;
172 exportSymbolDescriptors(aProps
, rName
);
175 OSL_FAIL("this type is not implemented now");
182 void XMLSettingsExportHelper::exportBool(const bool bValue
, const OUString
& rName
) const
184 DBG_ASSERT(!rName
.isEmpty(), "no name");
185 m_rContext
.AddAttribute( XML_NAME
, rName
);
186 m_rContext
.AddAttribute( XML_TYPE
, XML_BOOLEAN
);
187 m_rContext
.StartElement( XML_CONFIG_ITEM
);
190 sValue
= GetXMLToken(XML_TRUE
);
192 sValue
= GetXMLToken(XML_FALSE
);
193 m_rContext
.Characters( sValue
);
194 m_rContext
.EndElement( false );
197 void XMLSettingsExportHelper::exportByte()
199 OSL_ENSURE(false, "XMLSettingsExportHelper::exportByte(): #i114162#:\n"
200 "config-items of type \"byte\" are not valid ODF, "
201 "so storing them is disabled!\n"
202 "Use a different type instead (e.g. \"short\").");
204 void XMLSettingsExportHelper::exportShort(const sal_Int16 nValue
, const OUString
& rName
) const
206 DBG_ASSERT(!rName
.isEmpty(), "no name");
207 m_rContext
.AddAttribute( XML_NAME
, rName
);
208 m_rContext
.AddAttribute( XML_TYPE
, XML_SHORT
);
209 m_rContext
.StartElement( XML_CONFIG_ITEM
);
210 m_rContext
.Characters( OUString::number(nValue
) );
211 m_rContext
.EndElement( false );
214 void XMLSettingsExportHelper::exportInt(const sal_Int32 nValue
, const OUString
& rName
) const
216 DBG_ASSERT(!rName
.isEmpty(), "no name");
217 m_rContext
.AddAttribute( XML_NAME
, rName
);
218 m_rContext
.AddAttribute( XML_TYPE
, XML_INT
);
219 m_rContext
.StartElement( XML_CONFIG_ITEM
);
220 m_rContext
.Characters( OUString::number(nValue
) );
221 m_rContext
.EndElement( false );
224 void XMLSettingsExportHelper::exportLong(const sal_Int64 nValue
, const OUString
& rName
) const
226 DBG_ASSERT(!rName
.isEmpty(), "no name");
227 m_rContext
.AddAttribute( XML_NAME
, rName
);
228 m_rContext
.AddAttribute( XML_TYPE
, XML_LONG
);
229 m_rContext
.StartElement( XML_CONFIG_ITEM
);
230 m_rContext
.Characters( OUString::number(nValue
) );
231 m_rContext
.EndElement( false );
234 void XMLSettingsExportHelper::exportDouble(const double fValue
, const OUString
& rName
) const
236 DBG_ASSERT(!rName
.isEmpty(), "no name");
237 m_rContext
.AddAttribute( XML_NAME
, rName
);
238 m_rContext
.AddAttribute( XML_TYPE
, XML_DOUBLE
);
239 m_rContext
.StartElement( XML_CONFIG_ITEM
);
240 OUStringBuffer sBuffer
;
241 ::sax::Converter::convertDouble(sBuffer
, fValue
);
242 m_rContext
.Characters( sBuffer
.makeStringAndClear() );
243 m_rContext
.EndElement( false );
246 void XMLSettingsExportHelper::exportString(const OUString
& sValue
, const OUString
& rName
) const
248 DBG_ASSERT(!rName
.isEmpty(), "no name");
249 m_rContext
.AddAttribute( XML_NAME
, rName
);
250 m_rContext
.AddAttribute( XML_TYPE
, XML_STRING
);
251 m_rContext
.StartElement( XML_CONFIG_ITEM
);
252 if (!sValue
.isEmpty())
253 m_rContext
.Characters( sValue
);
254 m_rContext
.EndElement( false );
257 void XMLSettingsExportHelper::exportDateTime(const util::DateTime
& aValue
, const OUString
& rName
) const
259 DBG_ASSERT(!rName
.isEmpty(), "no name");
260 m_rContext
.AddAttribute( XML_NAME
, rName
);
261 m_rContext
.AddAttribute( XML_TYPE
, XML_DATETIME
);
262 OUStringBuffer sBuffer
;
263 ::sax::Converter::convertDateTime(sBuffer
, aValue
, nullptr);
264 m_rContext
.StartElement( XML_CONFIG_ITEM
);
265 m_rContext
.Characters( sBuffer
.makeStringAndClear() );
266 m_rContext
.EndElement( false );
269 void XMLSettingsExportHelper::exportSequencePropertyValue(
270 const uno::Sequence
<beans::PropertyValue
>& aProps
,
271 const OUString
& rName
) const
273 DBG_ASSERT(!rName
.isEmpty(), "no name");
274 if(aProps
.hasElements())
276 m_rContext
.AddAttribute( XML_NAME
, rName
);
277 m_rContext
.StartElement( XML_CONFIG_ITEM_SET
);
278 for (const auto& rProp
: aProps
)
279 CallTypeFunction(rProp
.Value
, rProp
.Name
);
280 m_rContext
.EndElement( true );
283 void XMLSettingsExportHelper::exportSymbolDescriptors(
284 const uno::Sequence
< formula::SymbolDescriptor
> &rProps
,
285 const OUString
& rName
) const
287 uno::Reference
< container::XIndexContainer
> xBox
= document::IndexedPropertyValues::create(m_rContext
.GetComponentContext());
289 const OUString
sName ( "Name" );
290 const OUString
sExportName ( "ExportName" );
291 const OUString
sSymbolSet ( "SymbolSet" );
292 const OUString
sCharacter ( "Character" );
293 const OUString
sFontName ( "FontName" );
294 const OUString
sCharSet ( "CharSet" );
295 const OUString
sFamily ( "Family" );
296 const OUString
sPitch ( "Pitch" );
297 const OUString
sWeight ( "Weight" );
298 const OUString
sItalic ( "Italic" );
300 sal_Int32 nCount
= rProps
.getLength();
301 const formula::SymbolDescriptor
*pDescriptor
= rProps
.getConstArray();
303 for( sal_Int32 nIndex
= 0; nIndex
< nCount
; nIndex
++, pDescriptor
++ )
305 uno::Sequence
< beans::PropertyValue
> aSequence ( XML_SYMBOL_DESCRIPTOR_MAX
);
306 beans::PropertyValue
*pSymbol
= aSequence
.getArray();
308 pSymbol
[XML_SYMBOL_DESCRIPTOR_NAME
].Name
= sName
;
309 pSymbol
[XML_SYMBOL_DESCRIPTOR_NAME
].Value
<<= pDescriptor
->sName
;
310 pSymbol
[XML_SYMBOL_DESCRIPTOR_EXPORT_NAME
].Name
= sExportName
;
311 pSymbol
[XML_SYMBOL_DESCRIPTOR_EXPORT_NAME
].Value
<<= pDescriptor
->sExportName
;
312 pSymbol
[XML_SYMBOL_DESCRIPTOR_FONT_NAME
].Name
= sFontName
;
313 pSymbol
[XML_SYMBOL_DESCRIPTOR_FONT_NAME
].Value
<<= pDescriptor
->sFontName
;
314 pSymbol
[XML_SYMBOL_DESCRIPTOR_CHAR_SET
].Name
= sCharSet
;
315 pSymbol
[XML_SYMBOL_DESCRIPTOR_CHAR_SET
].Value
<<= pDescriptor
->nCharSet
;
316 pSymbol
[XML_SYMBOL_DESCRIPTOR_FAMILY
].Name
= sFamily
;
317 pSymbol
[XML_SYMBOL_DESCRIPTOR_FAMILY
].Value
<<= pDescriptor
->nFamily
;
318 pSymbol
[XML_SYMBOL_DESCRIPTOR_PITCH
].Name
= sPitch
;
319 pSymbol
[XML_SYMBOL_DESCRIPTOR_PITCH
].Value
<<= pDescriptor
->nPitch
;
320 pSymbol
[XML_SYMBOL_DESCRIPTOR_WEIGHT
].Name
= sWeight
;
321 pSymbol
[XML_SYMBOL_DESCRIPTOR_WEIGHT
].Value
<<= pDescriptor
->nWeight
;
322 pSymbol
[XML_SYMBOL_DESCRIPTOR_ITALIC
].Name
= sItalic
;
323 pSymbol
[XML_SYMBOL_DESCRIPTOR_ITALIC
].Value
<<= pDescriptor
->nItalic
;
324 pSymbol
[XML_SYMBOL_DESCRIPTOR_SYMBOL_SET
].Name
= sSymbolSet
;
325 pSymbol
[XML_SYMBOL_DESCRIPTOR_SYMBOL_SET
].Value
<<= pDescriptor
->sSymbolSet
;
326 pSymbol
[XML_SYMBOL_DESCRIPTOR_CHARACTER
].Name
= sCharacter
;
327 pSymbol
[XML_SYMBOL_DESCRIPTOR_CHARACTER
].Value
<<= pDescriptor
->nCharacter
;
329 xBox
->insertByIndex(nIndex
, uno::makeAny( aSequence
));
332 exportIndexAccess( xBox
, rName
);
334 void XMLSettingsExportHelper::exportbase64Binary(
335 const uno::Sequence
<sal_Int8
>& aProps
,
336 const OUString
& rName
) const
338 DBG_ASSERT(!rName
.isEmpty(), "no name");
339 m_rContext
.AddAttribute( XML_NAME
, rName
);
340 m_rContext
.AddAttribute( XML_TYPE
, XML_BASE64BINARY
);
341 m_rContext
.StartElement( XML_CONFIG_ITEM
);
342 if(aProps
.hasElements())
344 OUStringBuffer sBuffer
;
345 ::comphelper::Base64::encode(sBuffer
, aProps
);
346 m_rContext
.Characters( sBuffer
.makeStringAndClear() );
348 m_rContext
.EndElement( false );
351 void XMLSettingsExportHelper::exportMapEntry(const uno::Any
& rAny
,
352 const OUString
& rName
,
353 const bool bNameAccess
) const
355 DBG_ASSERT((bNameAccess
&& !rName
.isEmpty()) || !bNameAccess
, "no name");
356 uno::Sequence
<beans::PropertyValue
> aProps
;
358 if (aProps
.hasElements())
361 m_rContext
.AddAttribute( XML_NAME
, rName
);
362 m_rContext
.StartElement( XML_CONFIG_ITEM_MAP_ENTRY
);
363 for (const auto& rProp
: std::as_const(aProps
))
364 CallTypeFunction(rProp
.Value
, rProp
.Name
);
365 m_rContext
.EndElement( true );
369 void XMLSettingsExportHelper::exportNameAccess(
370 const uno::Reference
<container::XNameAccess
>& aNamed
,
371 const OUString
& rName
) const
373 DBG_ASSERT(!rName
.isEmpty(), "no name");
374 DBG_ASSERT(aNamed
->getElementType().equals(cppu::UnoType
<uno::Sequence
<beans::PropertyValue
>>::get() ),
375 "wrong NameAccess" );
376 if(aNamed
->hasElements())
378 m_rContext
.AddAttribute( XML_NAME
, rName
);
379 m_rContext
.StartElement( XML_CONFIG_ITEM_MAP_NAMED
);
380 const uno::Sequence
< OUString
> aNames(aNamed
->getElementNames());
381 for (const auto& rElementName
: aNames
)
382 exportMapEntry(aNamed
->getByName(rElementName
), rElementName
, true);
383 m_rContext
.EndElement( true );
387 void XMLSettingsExportHelper::exportIndexAccess(
388 const uno::Reference
<container::XIndexAccess
>& rIndexed
,
389 const OUString
& rName
) const
391 DBG_ASSERT(!rName
.isEmpty(), "no name");
392 DBG_ASSERT(rIndexed
->getElementType().equals(cppu::UnoType
<uno::Sequence
<beans::PropertyValue
>>::get() ),
393 "wrong IndexAccess" );
394 if (rIndexed
->hasElements())
396 m_rContext
.AddAttribute( XML_NAME
, rName
);
397 m_rContext
.StartElement( XML_CONFIG_ITEM_MAP_INDEXED
);
398 sal_Int32 nCount
= rIndexed
->getCount();
399 for (sal_Int32 i
= 0; i
< nCount
; i
++)
401 exportMapEntry(rIndexed
->getByIndex(i
), "", false);
403 m_rContext
.EndElement( true );
407 void XMLSettingsExportHelper::exportForbiddenCharacters(
408 const uno::Any
&rAny
,
409 const OUString
& rName
) const
411 uno::Reference
<i18n::XForbiddenCharacters
> xForbChars
;
412 uno::Reference
<linguistic2::XSupportedLocales
> xLocales
;
417 SAL_WARN_IF( !(xForbChars
.is() && xLocales
.is()), "xmloff","XMLSettingsExportHelper::exportForbiddenCharacters: got illegal forbidden characters!" );
419 if( !xForbChars
.is() || !xLocales
.is() )
422 uno::Reference
< container::XIndexContainer
> xBox
= document::IndexedPropertyValues::create(m_rContext
.GetComponentContext());
423 const uno::Sequence
< lang::Locale
> aLocales( xLocales
->getLocales() );
425 /* FIXME-BCP47: this stupid and counterpart in
426 * xmloff/source/core/DocumentSettingsContext.cxx
427 * XMLConfigItemMapIndexedContext::EndElement() */
429 const OUString
sLanguage ( "Language" );
430 const OUString
sCountry ( "Country" );
431 const OUString
sVariant ( "Variant" );
432 const OUString
sBeginLine ( "BeginLine" );
433 const OUString
sEndLine ( "EndLine" );
436 for( const auto& rLocale
: aLocales
)
438 if( xForbChars
->hasForbiddenCharacters( rLocale
) )
440 const i18n::ForbiddenCharacters
aChars( xForbChars
->getForbiddenCharacters( rLocale
) );
443 uno::Sequence
< beans::PropertyValue
> aSequence ( XML_FORBIDDEN_CHARACTER_MAX
);
444 beans::PropertyValue
*pForChar
= aSequence
.getArray();
446 pForChar
[XML_FORBIDDEN_CHARACTER_LANGUAGE
].Name
= sLanguage
;
447 pForChar
[XML_FORBIDDEN_CHARACTER_LANGUAGE
].Value
<<= rLocale
.Language
;
448 pForChar
[XML_FORBIDDEN_CHARACTER_COUNTRY
].Name
= sCountry
;
449 pForChar
[XML_FORBIDDEN_CHARACTER_COUNTRY
].Value
<<= rLocale
.Country
;
450 pForChar
[XML_FORBIDDEN_CHARACTER_VARIANT
].Name
= sVariant
;
451 pForChar
[XML_FORBIDDEN_CHARACTER_VARIANT
].Value
<<= rLocale
.Variant
;
452 pForChar
[XML_FORBIDDEN_CHARACTER_BEGIN_LINE
].Name
= sBeginLine
;
453 pForChar
[XML_FORBIDDEN_CHARACTER_BEGIN_LINE
].Value
<<= aChars
.beginLine
;
454 pForChar
[XML_FORBIDDEN_CHARACTER_END_LINE
].Name
= sEndLine
;
455 pForChar
[XML_FORBIDDEN_CHARACTER_END_LINE
].Value
<<= aChars
.endLine
;
456 xBox
->insertByIndex(nPos
++, uno::makeAny( aSequence
));
460 exportIndexAccess( xBox
, rName
);
463 void XMLSettingsExportHelper::exportAllSettings(
464 const uno::Sequence
<beans::PropertyValue
>& aProps
,
465 const OUString
& rName
) const
467 DBG_ASSERT(!rName
.isEmpty(), "no name");
468 exportSequencePropertyValue(aProps
, rName
);
472 /** For some settings we may want to change their API representation
473 * from their XML settings representation. This is your chance to do
476 void XMLSettingsExportHelper::ManipulateSetting( uno::Any
& rAny
, const OUString
& rName
) const
478 if( rName
== gsPrinterIndependentLayout
)
480 sal_Int16 nTmp
= sal_Int16();
483 if( nTmp
== document::PrinterIndependentLayout::LOW_RESOLUTION
)
484 rAny
<<= OUString("low-resolution");
485 else if( nTmp
== document::PrinterIndependentLayout::DISABLED
)
486 rAny
<<= OUString("disabled");
487 else if( nTmp
== document::PrinterIndependentLayout::HIGH_RESOLUTION
)
488 rAny
<<= OUString("high-resolution");
491 else if( (rName
== gsColorTableURL
) || (rName
== gsLineEndTableURL
) || (rName
== gsHatchTableURL
) ||
492 (rName
== gsDashTableURL
) || (rName
== gsGradientTableURL
) || (rName
== gsBitmapTableURL
) )
494 if( !mxStringSubstitution
.is() )
498 const_cast< XMLSettingsExportHelper
* >(this)->mxStringSubstitution
=
499 util::PathSubstitution::create( m_rContext
.GetComponentContext() );
501 catch( uno::Exception
& )
503 DBG_UNHANDLED_EXCEPTION("xmloff.core");
507 if( mxStringSubstitution
.is() )
511 aURL
= mxStringSubstitution
->reSubstituteVariables( aURL
);
517 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */