Update git submodules
[LibreOffice.git] / xmloff / source / core / SettingsExportHelper.cxx
blob3f6f87fa1bbb11aeca1c8bf72119fcba07838814
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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();
74 switch (eClass)
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");
85 break;
86 case uno::TypeClass_BOOLEAN:
88 exportBool(::cppu::any2bool(aAny), rName);
90 break;
91 case uno::TypeClass_BYTE:
93 exportByte();
95 break;
96 case uno::TypeClass_SHORT:
98 sal_Int16 nInt16 = 0;
99 aAny >>= nInt16;
100 exportShort(nInt16, rName);
102 break;
103 case uno::TypeClass_LONG:
105 sal_Int32 nInt32 = 0;
106 aAny >>= nInt32;
107 exportInt(nInt32, rName);
109 break;
110 case uno::TypeClass_HYPER:
112 sal_Int64 nInt64 = 0;
113 aAny >>= nInt64;
114 exportLong(nInt64, rName);
116 break;
117 case uno::TypeClass_DOUBLE:
119 double fDouble = 0.0;
120 aAny >>= fDouble;
121 exportDouble(fDouble, rName);
123 break;
124 case uno::TypeClass_STRING:
126 OUString sString;
127 aAny >>= sString;
128 exportString(sString, rName);
130 break;
131 default:
133 const uno::Type& aType = aAny.getValueType();
134 if (aType.equals(cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get() ) )
136 uno::Sequence< beans::PropertyValue> aProps;
137 aAny >>= aProps;
138 exportSequencePropertyValue(aProps, rName);
140 else if( aType.equals(cppu::UnoType<uno::Sequence<sal_Int8>>::get() ) )
142 uno::Sequence< sal_Int8 > aProps;
143 aAny >>= 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;
157 aAny >>= 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;
167 aAny >>= aProps;
168 exportSymbolDescriptors(aProps, rName);
170 else {
171 OSL_FAIL("this type is not implemented now");
174 break;
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 );
184 OUString sValue;
185 if (bValue)
186 sValue = GetXMLToken(XML_TRUE);
187 else
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"))
282 continue;
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;
362 rAny >>= aProps;
363 if (aProps.hasElements())
365 if (bNameAccess)
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() )
421 return;
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" );
436 sal_Int32 nPos = 0;
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
475 * so!
477 void XMLSettingsExportHelper::ManipulateSetting( uno::Any& rAny, std::u16string_view rName ) const
479 if( rName == gsPrinterIndependentLayout )
481 sal_Int16 nTmp = sal_Int16();
482 if( rAny >>= nTmp )
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() )
510 OUString aURL;
511 rAny >>= aURL;
512 aURL = mxStringSubstitution->reSubstituteVariables( aURL );
513 rAny <<= aURL;
518 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */