1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 
21 #include <sax/tools/converter.hxx>
22 
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>
30 
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"
44 
45 using namespace ::com::sun::star;
46 using namespace ::xmloff::token;
47 
48 static const OUStringLiteral gsPrinterIndependentLayout( "PrinterIndependentLayout" );
49 static const OUStringLiteral gsColorTableURL( "ColorTableURL" );
50 static const OUStringLiteral gsLineEndTableURL( "LineEndTableURL" );
51 static const OUStringLiteral gsHatchTableURL( "HatchTableURL" );
52 static const OUStringLiteral gsDashTableURL( "DashTableURL" );
53 static const OUStringLiteral gsGradientTableURL( "GradientTableURL" );
54 static const OUStringLiteral gsBitmapTableURL( "BitmapTableURL" );
55 
XMLSettingsExportHelper(::xmloff::XMLSettingsExportContext & i_rContext)56 XMLSettingsExportHelper::XMLSettingsExportHelper( ::xmloff::XMLSettingsExportContext& i_rContext )
57 : m_rContext( i_rContext )
58 {
59 }
60 
~XMLSettingsExportHelper()61 XMLSettingsExportHelper::~XMLSettingsExportHelper()
62 {
63 }
64 
CallTypeFunction(const uno::Any & rAny,const OUString & rName) const65 void XMLSettingsExportHelper::CallTypeFunction(const uno::Any& rAny,
66                                             const OUString& rName) const
67 {
68     uno::Any aAny( rAny );
69     ManipulateSetting( aAny, rName );
70 
71     uno::TypeClass eClass = aAny.getValueTypeClass();
72     switch (eClass)
73     {
74         case uno::TypeClass_VOID:
75         {
76             /*
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");
81              */
82         }
83         break;
84         case uno::TypeClass_BOOLEAN:
85         {
86             exportBool(::cppu::any2bool(aAny), rName);
87         }
88         break;
89         case uno::TypeClass_BYTE:
90         {
91             exportByte();
92         }
93         break;
94         case uno::TypeClass_SHORT:
95         {
96             sal_Int16 nInt16 = 0;
97             aAny >>= nInt16;
98             exportShort(nInt16, rName);
99         }
100         break;
101         case uno::TypeClass_LONG:
102         {
103             sal_Int32 nInt32 = 0;
104             aAny >>= nInt32;
105             exportInt(nInt32, rName);
106         }
107         break;
108         case uno::TypeClass_HYPER:
109         {
110             sal_Int64 nInt64 = 0;
111             aAny >>= nInt64;
112             exportLong(nInt64, rName);
113         }
114         break;
115         case uno::TypeClass_DOUBLE:
116         {
117             double fDouble = 0.0;
118             aAny >>= fDouble;
119             exportDouble(fDouble, rName);
120         }
121         break;
122         case uno::TypeClass_STRING:
123         {
124             OUString sString;
125             aAny >>= sString;
126             exportString(sString, rName);
127         }
128         break;
129         default:
130         {
131             const uno::Type& aType = aAny.getValueType();
132             if (aType.equals(cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get() ) )
133             {
134                 uno::Sequence< beans::PropertyValue> aProps;
135                 aAny >>= aProps;
136                 exportSequencePropertyValue(aProps, rName);
137             }
138             else if( aType.equals(cppu::UnoType<uno::Sequence<sal_Int8>>::get() ) )
139             {
140                 uno::Sequence< sal_Int8 > aProps;
141                 aAny >>= aProps;
142                 exportbase64Binary(aProps, rName);
143             }
144             else if (aType.equals(cppu::UnoType<container::XNameContainer>::get()) ||
145                     aType.equals(cppu::UnoType<container::XNameAccess>::get()))
146             {
147                 uno::Reference< container::XNameAccess> aNamed;
148                 aAny >>= aNamed;
149                 exportNameAccess(aNamed, rName);
150             }
151             else if (aType.equals(cppu::UnoType<container::XIndexAccess>::get()) ||
152                     aType.equals(cppu::UnoType<container::XIndexContainer>::get()) )
153             {
154                 uno::Reference<container::XIndexAccess> aIndexed;
155                 aAny >>= aIndexed;
156                 exportIndexAccess(aIndexed, rName);
157             }
158             else if (aType.equals(cppu::UnoType<util::DateTime>::get()) )
159             {
160                 util::DateTime aDateTime;
161                 aAny >>= aDateTime;
162                 exportDateTime(aDateTime, rName);
163             }
164             else if( aType.equals(cppu::UnoType<i18n::XForbiddenCharacters>::get()) )
165             {
166                 exportForbiddenCharacters( aAny, rName );
167             }
168             else if( aType.equals(cppu::UnoType<uno::Sequence<formula::SymbolDescriptor>>::get() ) )
169             {
170                 uno::Sequence< formula::SymbolDescriptor > aProps;
171                 aAny >>= aProps;
172                 exportSymbolDescriptors(aProps, rName);
173             }
174             else {
175                 OSL_FAIL("this type is not implemented now");
176             }
177         }
178         break;
179     }
180 }
181 
exportBool(const bool bValue,const OUString & rName) const182 void XMLSettingsExportHelper::exportBool(const bool bValue, const OUString& rName) const
183 {
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 );
188     OUString sValue;
189     if (bValue)
190         sValue = GetXMLToken(XML_TRUE);
191     else
192         sValue = GetXMLToken(XML_FALSE);
193     m_rContext.Characters( sValue );
194     m_rContext.EndElement( false );
195 }
196 
exportByte()197 void XMLSettingsExportHelper::exportByte()
198 {
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\").");
203 }
exportShort(const sal_Int16 nValue,const OUString & rName) const204 void XMLSettingsExportHelper::exportShort(const sal_Int16 nValue, const OUString& rName) const
205 {
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 );
212 }
213 
exportInt(const sal_Int32 nValue,const OUString & rName) const214 void XMLSettingsExportHelper::exportInt(const sal_Int32 nValue, const OUString& rName) const
215 {
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 );
222 }
223 
exportLong(const sal_Int64 nValue,const OUString & rName) const224 void XMLSettingsExportHelper::exportLong(const sal_Int64 nValue, const OUString& rName) const
225 {
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 );
232 }
233 
exportDouble(const double fValue,const OUString & rName) const234 void XMLSettingsExportHelper::exportDouble(const double fValue, const OUString& rName) const
235 {
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 );
244 }
245 
exportString(const OUString & sValue,const OUString & rName) const246 void XMLSettingsExportHelper::exportString(const OUString& sValue, const OUString& rName) const
247 {
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 );
255 }
256 
exportDateTime(const util::DateTime & aValue,const OUString & rName) const257 void XMLSettingsExportHelper::exportDateTime(const util::DateTime& aValue, const OUString& rName) const
258 {
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 );
267 }
268 
exportSequencePropertyValue(const uno::Sequence<beans::PropertyValue> & aProps,const OUString & rName) const269 void XMLSettingsExportHelper::exportSequencePropertyValue(
270                     const uno::Sequence<beans::PropertyValue>& aProps,
271                     const OUString& rName) const
272 {
273     DBG_ASSERT(!rName.isEmpty(), "no name");
274     if(aProps.hasElements())
275     {
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 );
281     }
282 }
exportSymbolDescriptors(const uno::Sequence<formula::SymbolDescriptor> & rProps,const OUString & rName) const283 void XMLSettingsExportHelper::exportSymbolDescriptors(
284                     const uno::Sequence < formula::SymbolDescriptor > &rProps,
285                     const OUString& rName) const
286 {
287     uno::Reference< container::XIndexContainer > xBox = document::IndexedPropertyValues::create(m_rContext.GetComponentContext());
288 
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" );
299 
300     sal_Int32 nCount = rProps.getLength();
301     const formula::SymbolDescriptor *pDescriptor = rProps.getConstArray();
302 
303     for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++, pDescriptor++ )
304     {
305         uno::Sequence < beans::PropertyValue > aSequence ( XML_SYMBOL_DESCRIPTOR_MAX );
306         beans::PropertyValue *pSymbol = aSequence.getArray();
307 
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;
328 
329         xBox->insertByIndex(nIndex, uno::makeAny( aSequence ));
330     }
331 
332     exportIndexAccess( xBox, rName );
333 }
exportbase64Binary(const uno::Sequence<sal_Int8> & aProps,const OUString & rName) const334 void XMLSettingsExportHelper::exportbase64Binary(
335                     const uno::Sequence<sal_Int8>& aProps,
336                     const OUString& rName) const
337 {
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())
343     {
344         OUStringBuffer sBuffer;
345         ::comphelper::Base64::encode(sBuffer, aProps);
346         m_rContext.Characters( sBuffer.makeStringAndClear() );
347     }
348     m_rContext.EndElement( false );
349 }
350 
exportMapEntry(const uno::Any & rAny,const OUString & rName,const bool bNameAccess) const351 void XMLSettingsExportHelper::exportMapEntry(const uno::Any& rAny,
352                                         const OUString& rName,
353                                         const bool bNameAccess) const
354 {
355     DBG_ASSERT((bNameAccess && !rName.isEmpty()) || !bNameAccess, "no name");
356     uno::Sequence<beans::PropertyValue> aProps;
357     rAny >>= aProps;
358     if (aProps.hasElements())
359     {
360         if (bNameAccess)
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 );
366     }
367 }
368 
exportNameAccess(const uno::Reference<container::XNameAccess> & aNamed,const OUString & rName) const369 void XMLSettingsExportHelper::exportNameAccess(
370                     const uno::Reference<container::XNameAccess>& aNamed,
371                     const OUString& rName) const
372 {
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())
377     {
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 );
384     }
385 }
386 
exportIndexAccess(const uno::Reference<container::XIndexAccess> & rIndexed,const OUString & rName) const387 void XMLSettingsExportHelper::exportIndexAccess(
388                     const uno::Reference<container::XIndexAccess>& rIndexed,
389                     const OUString& rName) const
390 {
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())
395     {
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++)
400         {
401             exportMapEntry(rIndexed->getByIndex(i), "", false);
402         }
403         m_rContext.EndElement( true );
404     }
405 }
406 
exportForbiddenCharacters(const uno::Any & rAny,const OUString & rName) const407 void XMLSettingsExportHelper::exportForbiddenCharacters(
408                     const uno::Any &rAny,
409                     const OUString& rName) const
410 {
411     uno::Reference<i18n::XForbiddenCharacters> xForbChars;
412     uno::Reference<linguistic2::XSupportedLocales> xLocales;
413 
414     rAny >>= xForbChars;
415     rAny >>= xLocales;
416 
417     SAL_WARN_IF( !(xForbChars.is() && xLocales.is()), "xmloff","XMLSettingsExportHelper::exportForbiddenCharacters: got illegal forbidden characters!" );
418 
419     if( !xForbChars.is() || !xLocales.is() )
420         return;
421 
422     uno::Reference< container::XIndexContainer > xBox = document::IndexedPropertyValues::create(m_rContext.GetComponentContext());
423     const uno::Sequence< lang::Locale > aLocales( xLocales->getLocales() );
424 
425     /* FIXME-BCP47: this stupid and counterpart in
426      * xmloff/source/core/DocumentSettingsContext.cxx
427      * XMLConfigItemMapIndexedContext::EndElement() */
428 
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" );
434 
435     sal_Int32 nPos = 0;
436     for( const auto& rLocale : aLocales )
437     {
438         if( xForbChars->hasForbiddenCharacters( rLocale ) )
439         {
440             const i18n::ForbiddenCharacters aChars( xForbChars->getForbiddenCharacters( rLocale ) );
441 
442 
443             uno::Sequence < beans::PropertyValue > aSequence ( XML_FORBIDDEN_CHARACTER_MAX );
444             beans::PropertyValue *pForChar = aSequence.getArray();
445 
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 ));
457         }
458     }
459 
460     exportIndexAccess( xBox, rName );
461 }
462 
exportAllSettings(const uno::Sequence<beans::PropertyValue> & aProps,const OUString & rName) const463 void XMLSettingsExportHelper::exportAllSettings(
464                     const uno::Sequence<beans::PropertyValue>& aProps,
465                     const OUString& rName) const
466 {
467     DBG_ASSERT(!rName.isEmpty(), "no name");
468     exportSequencePropertyValue(aProps, rName);
469 }
470 
471 
472 /** For some settings we may want to change their API representation
473  * from their XML settings representation. This is your chance to do
474  * so!
475  */
ManipulateSetting(uno::Any & rAny,const OUString & rName) const476 void XMLSettingsExportHelper::ManipulateSetting( uno::Any& rAny, const OUString& rName ) const
477 {
478     if( rName == gsPrinterIndependentLayout )
479     {
480         sal_Int16 nTmp = sal_Int16();
481         if( rAny >>= nTmp )
482         {
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");
489         }
490     }
491     else if( (rName == gsColorTableURL) || (rName == gsLineEndTableURL) || (rName == gsHatchTableURL) ||
492              (rName == gsDashTableURL) || (rName == gsGradientTableURL) || (rName == gsBitmapTableURL ) )
493     {
494         if( !mxStringSubsitution.is() )
495         {
496             try
497             {
498                 const_cast< XMLSettingsExportHelper* >(this)->mxStringSubsitution =
499                     util::PathSubstitution::create( m_rContext.GetComponentContext() );
500             }
501             catch( uno::Exception& )
502             {
503                 DBG_UNHANDLED_EXCEPTION("xmloff.core");
504             }
505         }
506 
507         if( mxStringSubsitution.is() )
508         {
509             OUString aURL;
510             rAny >>= aURL;
511             aURL = mxStringSubsitution->reSubstituteVariables( aURL );
512             rAny <<= aURL;
513         }
514     }
515 }
516 
517 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
518