1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include <rtl/ref.hxx>
30 #include <rtl/ustrbuf.hxx>
31 #include <com/sun/star/i18n/XCharacterClassification.hpp>
32 #include <com/sun/star/i18n/UnicodeType.hpp>
33 #include <com/sun/star/util/MeasureUnit.hpp>
34 #include <sax/tools/converter.hxx>
35 #include <comphelper/processfactory.hxx>
36 #include <xmloff/nmspmap.hxx>
37 #include "xmloff/xmlnmspe.hxx"
38 #include "IgnoreTContext.hxx"
39 #include "RenameElemTContext.hxx"
40 #include "ProcAttrTContext.hxx"
41 #include "ProcAddAttrTContext.hxx"
42 #include "MergeElemTContext.hxx"
43 #include "CreateElemTContext.hxx"
44 #include "MutableAttrList.hxx"
45 #include "TransformerActions.hxx"
46 #include "ElemTransformerAction.hxx"
47 #include "PropertyActionsOOo.hxx"
48 #include "TransformerTokenMap.hxx"
50 #include "TransformerBase.hxx"
51 #include "TContextVector.hxx"
53 using ::rtl::OUString
;
54 using ::rtl::OUStringBuffer
;
55 using namespace ::osl
;
56 using namespace ::xmloff::token
;
57 using namespace ::com::sun::star
;
58 using namespace ::com::sun::star::uno
;
59 using namespace ::com::sun::star::beans
;
60 using namespace ::com::sun::star::lang
;
61 using namespace ::com::sun::star::i18n
;
62 using namespace ::com::sun::star::xml::sax
;
66 bool lcl_ConvertAttr( OUString
& rOutAttribute
, sal_Int32 nParam
)
69 enum XMLTokenEnum eTokenToRename
=
70 static_cast< enum XMLTokenEnum
>( nParam
& 0xffff );
71 if( eTokenToRename
!= XML_TOKEN_INVALID
&&
72 IsXMLToken( rOutAttribute
, eTokenToRename
))
74 enum XMLTokenEnum eReplacementToken
=
75 static_cast< enum XMLTokenEnum
>( nParam
>> 16 );
76 rOutAttribute
= GetXMLToken( eReplacementToken
);
81 } // anonymous namespace
83 XMLTransformerContext
*XMLTransformerBase::CreateContext( sal_uInt16 nPrefix
,
84 const OUString
& rLocalName
, const OUString
& rQName
)
86 XMLTransformerActions::key_type
aKey( nPrefix
, rLocalName
);
87 XMLTransformerActions::const_iterator aIter
=
88 GetElemActions().find( aKey
);
90 if( !(aIter
== GetElemActions().end()) )
92 sal_uInt32 nActionType
= (*aIter
).second
.m_nActionType
;
93 if( (nActionType
& XML_ETACTION_USER_DEFINED
) != 0 )
95 XMLTransformerContext
*pContext
=
96 CreateUserDefinedContext( (*aIter
).second
,
98 OSL_ENSURE( pContext
&& !pContext
->IsPersistent(),
99 "unknown or not persistent action" );
103 switch( nActionType
)
105 case XML_ETACTION_COPY_CONTENT
:
106 return new XMLIgnoreTransformerContext( *this, rQName
, sal_False
,
108 case XML_ETACTION_COPY
:
109 return new XMLTransformerContext( *this, rQName
);
110 case XML_ETACTION_RENAME_ELEM
:
111 return new XMLRenameElemTransformerContext( *this, rQName
,
112 (*aIter
).second
.GetQNamePrefixFromParam1(),
113 (*aIter
).second
.GetQNameTokenFromParam1() );
114 case XML_ETACTION_RENAME_ELEM_ADD_ATTR
:
115 return new XMLRenameElemTransformerContext( *this, rQName
,
116 (*aIter
).second
.GetQNamePrefixFromParam1(),
117 (*aIter
).second
.GetQNameTokenFromParam1(),
118 (*aIter
).second
.GetQNamePrefixFromParam2(),
119 (*aIter
).second
.GetQNameTokenFromParam2(),
120 static_cast< XMLTokenEnum
>( (*aIter
).second
.m_nParam3
) );
121 case XML_ETACTION_RENAME_ELEM_PROC_ATTRS
:
122 return new XMLProcAttrTransformerContext( *this, rQName
,
123 (*aIter
).second
.GetQNamePrefixFromParam1(),
124 (*aIter
).second
.GetQNameTokenFromParam1(),
125 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam2
) );
126 case XML_ETACTION_RENAME_ELEM_ADD_PROC_ATTR
:
127 return new XMLProcAddAttrTransformerContext( *this, rQName
,
128 (*aIter
).second
.GetQNamePrefixFromParam1(),
129 (*aIter
).second
.GetQNameTokenFromParam1(),
130 static_cast< sal_uInt16
>(
131 (*aIter
).second
.m_nParam3
>> 16 ),
132 (*aIter
).second
.GetQNamePrefixFromParam2(),
133 (*aIter
).second
.GetQNameTokenFromParam2(),
134 static_cast< XMLTokenEnum
>(
135 (*aIter
).second
.m_nParam3
& 0xffff ) );
136 case XML_ETACTION_RENAME_ELEM_COND
:
138 const XMLTransformerContext
*pCurrent
= GetCurrentContext();
139 if( pCurrent
->HasQName(
140 (*aIter
).second
.GetQNamePrefixFromParam2(),
141 (*aIter
).second
.GetQNameTokenFromParam2() ) )
142 return new XMLRenameElemTransformerContext( *this, rQName
,
143 (*aIter
).second
.GetQNamePrefixFromParam1(),
144 (*aIter
).second
.GetQNameTokenFromParam1() );
147 case XML_ETACTION_RENAME_ELEM_PROC_ATTRS_COND
:
149 const XMLTransformerContext
*pCurrent
= GetCurrentContext();
150 if( pCurrent
->HasQName(
151 (*aIter
).second
.GetQNamePrefixFromParam3(),
152 (*aIter
).second
.GetQNameTokenFromParam3() ) )
153 return new XMLProcAttrTransformerContext( *this, rQName
,
154 (*aIter
).second
.GetQNamePrefixFromParam1(),
155 (*aIter
).second
.GetQNameTokenFromParam1(),
156 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam2
) );
158 return new XMLProcAttrTransformerContext( *this, rQName
,
159 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam2
) );
161 case XML_ETACTION_PROC_ATTRS
:
162 return new XMLProcAttrTransformerContext( *this, rQName
,
163 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam1
) );
164 case XML_ETACTION_PROC_ATTRS_COND
:
166 const XMLTransformerContext
*pCurrent
= GetCurrentContext();
167 if( pCurrent
->HasQName(
168 (*aIter
).second
.GetQNamePrefixFromParam1(),
169 (*aIter
).second
.GetQNameTokenFromParam1() ) )
170 return new XMLProcAttrTransformerContext( *this, rQName
,
171 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam2
) );
174 case XML_ETACTION_MOVE_ATTRS_TO_ELEMS
:
175 return new XMLCreateElemTransformerContext( *this, rQName
,
176 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam1
) );
177 case XML_ETACTION_MOVE_ELEMS_TO_ATTRS
:
178 return new XMLMergeElemTransformerContext( *this, rQName
,
179 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam1
) );
181 OSL_ENSURE( !this, "unknown action" );
186 // default is copying
187 return new XMLTransformerContext( *this, rQName
);
190 XMLTransformerActions
*XMLTransformerBase::GetUserDefinedActions( sal_uInt16
)
195 XMLTransformerBase::XMLTransformerBase( XMLTransformerActionInit
*pInit
,
196 ::xmloff::token::XMLTokenEnum
*pTKMapInit
)
198 m_pNamespaceMap( new SvXMLNamespaceMap
),
199 m_pReplaceNamespaceMap( new SvXMLNamespaceMap
),
200 m_pContexts( new XMLTransformerContextVector
),
201 m_pElemActions( new XMLTransformerActions( pInit
) ),
202 m_pTokenMap( new XMLTransformerTokenMap( pTKMapInit
) )
204 GetNamespaceMap().Add( GetXMLToken(XML_NP_XLINK
), GetXMLToken(XML_N_XLINK
), XML_NAMESPACE_XLINK
);
205 GetNamespaceMap().Add( GetXMLToken(XML_NP_DC
), GetXMLToken(XML_N_DC
), XML_NAMESPACE_DC
);
206 GetNamespaceMap().Add( GetXMLToken(XML_NP_MATH
), GetXMLToken(XML_N_MATH
), XML_NAMESPACE_MATH
);
207 GetNamespaceMap().Add( GetXMLToken(XML_NP_OOO
), GetXMLToken(XML_N_OOO
), XML_NAMESPACE_OOO
);
208 GetNamespaceMap().Add( GetXMLToken(XML_NP_DOM
), GetXMLToken(XML_N_DOM
), XML_NAMESPACE_DOM
);
209 GetNamespaceMap().Add( GetXMLToken(XML_NP_OOOW
), GetXMLToken(XML_N_OOOW
), XML_NAMESPACE_OOOW
);
210 GetNamespaceMap().Add( GetXMLToken(XML_NP_OOOC
), GetXMLToken(XML_N_OOOC
), XML_NAMESPACE_OOOC
);
213 XMLTransformerBase::~XMLTransformerBase() throw ()
217 delete m_pNamespaceMap
;
218 delete m_pReplaceNamespaceMap
;
220 delete m_pElemActions
;
224 void SAL_CALL
XMLTransformerBase::startDocument( void )
225 throw( SAXException
, RuntimeException
)
227 m_xHandler
->startDocument();
230 void SAL_CALL
XMLTransformerBase::endDocument( void )
231 throw( SAXException
, RuntimeException
)
233 m_xHandler
->endDocument();
236 void SAL_CALL
XMLTransformerBase::startElement( const OUString
& rName
,
237 const Reference
< XAttributeList
>& rAttrList
)
238 throw(SAXException
, RuntimeException
)
240 SvXMLNamespaceMap
*pRewindMap
= 0;
242 bool bRect
= rName
== "presentation:show-shape";
245 // Process namespace attributes. This must happen before creating the
246 // context, because namespace decaration apply to the element name itself.
247 XMLMutableAttributeList
*pMutableAttrList
= 0;
248 Reference
< XAttributeList
> xAttrList( rAttrList
);
249 sal_Int16 nAttrCount
= xAttrList
.is() ? xAttrList
->getLength() : 0;
250 for( sal_Int16 i
=0; i
< nAttrCount
; i
++ )
252 const OUString
& rAttrName
= xAttrList
->getNameByIndex( i
);
253 if( ( rAttrName
.getLength() >= 5 ) &&
254 ( rAttrName
.compareTo( GetXMLToken(XML_XMLNS
), 5 ) == 0 ) &&
255 ( rAttrName
.getLength() == 5 || ':' == rAttrName
[5] ) )
259 pRewindMap
= m_pNamespaceMap
;
260 m_pNamespaceMap
= new SvXMLNamespaceMap( *m_pNamespaceMap
);
262 const OUString
& rAttrValue
= xAttrList
->getValueByIndex( i
);
264 OUString
aPrefix( ( rAttrName
.getLength() == 5 )
266 : rAttrName
.copy( 6 ) );
267 // Add namespace, but only if it is known.
268 sal_uInt16 nKey
= m_pNamespaceMap
->AddIfKnown( aPrefix
, rAttrValue
);
269 // If namespace is unknwon, try to match a name with similar
271 if( XML_NAMESPACE_UNKNOWN
== nKey
)
273 OUString
aTestName( rAttrValue
);
274 if( SvXMLNamespaceMap::NormalizeOasisURN( aTestName
) )
275 nKey
= m_pNamespaceMap
->AddIfKnown( aPrefix
, aTestName
);
277 // If that namespace is not known, too, add it as unknown
278 if( XML_NAMESPACE_UNKNOWN
== nKey
)
279 nKey
= m_pNamespaceMap
->Add( aPrefix
, rAttrValue
);
281 const OUString
& rRepName
= m_pReplaceNamespaceMap
->GetNameByKey( nKey
);
282 if( !rRepName
.isEmpty() )
284 if( !pMutableAttrList
)
286 pMutableAttrList
= new XMLMutableAttributeList( xAttrList
);
287 xAttrList
= pMutableAttrList
;
290 pMutableAttrList
->SetValueByIndex( i
, rRepName
);
295 // Get element's namespace and local name.
298 m_pNamespaceMap
->GetKeyByAttrName( rName
, &aLocalName
);
300 // If there are contexts already, call a CreateChildContext at the topmost
301 // context. Otherwise, create a default context.
302 ::rtl::Reference
< XMLTransformerContext
> xContext
;
303 if( !m_pContexts
->empty() )
305 xContext
= m_pContexts
->back()->CreateChildContext( nPrefix
,
312 xContext
= CreateContext( nPrefix
, aLocalName
, rName
);
315 OSL_ENSURE( xContext
.is(), "XMLTransformerBase::startElement: missing context" );
317 xContext
= new XMLTransformerContext( *this, rName
);
319 // Remeber old namespace map.
321 xContext
->SetRewindMap( pRewindMap
);
323 // Push context on stack.
324 m_pContexts
->push_back( xContext
);
326 // Call a startElement at the new context.
327 xContext
->StartElement( xAttrList
);
330 void SAL_CALL
XMLTransformerBase::endElement( const OUString
&
331 #if OSL_DEBUG_LEVEL > 0
335 throw(SAXException
, RuntimeException
)
337 if( !m_pContexts
->empty() )
339 // Get topmost context
340 ::rtl::Reference
< XMLTransformerContext
> xContext
= m_pContexts
->back();
342 #if OSL_DEBUG_LEVEL > 0
343 OSL_ENSURE( xContext
->GetQName() == rName
,
344 "XMLTransformerBase::endElement: popped context has wrong lname" );
347 // Call a EndElement at the current context.
348 xContext
->EndElement();
350 // and remove it from the stack.
351 m_pContexts
->pop_back();
353 // Get a namespace map to rewind.
354 SvXMLNamespaceMap
*pRewindMap
= xContext
->GetRewindMap();
356 // Delete the current context.
359 // Rewind a namespace map.
362 delete m_pNamespaceMap
;
363 m_pNamespaceMap
= pRewindMap
;
368 void SAL_CALL
XMLTransformerBase::characters( const OUString
& rChars
)
369 throw(SAXException
, RuntimeException
)
371 if( !m_pContexts
->empty() )
373 m_pContexts
->back()->Characters( rChars
);
377 void SAL_CALL
XMLTransformerBase::ignorableWhitespace( const OUString
& rWhitespaces
)
378 throw(SAXException
, RuntimeException
)
380 m_xHandler
->ignorableWhitespace( rWhitespaces
);
383 void SAL_CALL
XMLTransformerBase::processingInstruction( const OUString
& rTarget
,
384 const OUString
& rData
)
385 throw(SAXException
, RuntimeException
)
387 m_xHandler
->processingInstruction( rTarget
, rData
);
390 void SAL_CALL
XMLTransformerBase::setDocumentLocator( const Reference
< XLocator
>& rLocator
)
391 throw(SAXException
, RuntimeException
)
393 m_xLocator
= rLocator
;
396 // XExtendedDocumentHandler
397 void SAL_CALL
XMLTransformerBase::startCDATA( void ) throw(SAXException
, RuntimeException
)
399 if( m_xExtHandler
.is() )
400 m_xExtHandler
->startCDATA();
403 void SAL_CALL
XMLTransformerBase::endCDATA( void ) throw(RuntimeException
)
405 if( m_xExtHandler
.is() )
406 m_xExtHandler
->endCDATA();
409 void SAL_CALL
XMLTransformerBase::comment( const OUString
& rComment
)
410 throw(SAXException
, RuntimeException
)
412 if( m_xExtHandler
.is() )
413 m_xExtHandler
->comment( rComment
);
416 void SAL_CALL
XMLTransformerBase::allowLineBreak( void )
417 throw(SAXException
, RuntimeException
)
419 if( m_xExtHandler
.is() )
420 m_xExtHandler
->allowLineBreak();
423 void SAL_CALL
XMLTransformerBase::unknown( const OUString
& rString
)
424 throw(SAXException
, RuntimeException
)
426 if( m_xExtHandler
.is() )
427 m_xExtHandler
->unknown( rString
);
431 void SAL_CALL
XMLTransformerBase::initialize( const Sequence
< Any
>& aArguments
)
432 throw(Exception
, RuntimeException
)
434 const sal_Int32 nAnyCount
= aArguments
.getLength();
435 const Any
* pAny
= aArguments
.getConstArray();
437 for( sal_Int32 nIndex
= 0; nIndex
< nAnyCount
; nIndex
++, pAny
++ )
439 // use isAssignableFrom instead of comparing the types to
440 // allow XExtendedDocumentHandler instead of XDocumentHandler (used in
441 // writeOasis2OOoLibraryElement in sfx2).
442 // The Any shift operator can't be used to query the type because it
443 // uses queryInterface, and the model also has a XPropertySet interface.
446 if( ::getCppuType( (const Reference
< XDocumentHandler
>*) 0 ).isAssignableFrom( pAny
->getValueType() ) )
447 m_xHandler
.set( *pAny
, UNO_QUERY
);
449 // property set to transport data across
450 if( ::getCppuType( (const Reference
< XPropertySet
>*) 0 ).isAssignableFrom( pAny
->getValueType() ) )
451 m_xPropSet
.set( *pAny
, UNO_QUERY
);
454 if( ::getCppuType( (const Reference
< ::com::sun::star::frame::XModel
>*) 0 ).isAssignableFrom( pAny
->getValueType() ) )
455 mxModel
.set( *pAny
, UNO_QUERY
);
458 if( m_xPropSet
.is() )
461 OUString sRelPath
, sName
;
462 Reference
< XPropertySetInfo
> xPropSetInfo
=
463 m_xPropSet
->getPropertySetInfo();
464 OUString
sPropName( "StreamRelPath" );
465 if( xPropSetInfo
->hasPropertyByName(sPropName
) )
467 aAny
= m_xPropSet
->getPropertyValue(sPropName
);
470 sPropName
= OUString( "StreamName" );
471 if( xPropSetInfo
->hasPropertyByName(sPropName
) )
473 aAny
= m_xPropSet
->getPropertyValue(sPropName
);
476 if( !sName
.isEmpty() )
478 m_aExtPathPrefix
= OUString( "../" );
480 // If there is a rel path within a package, then append
481 // additional '../'. If the rel path contains an ':', then it is
482 // an absolute URI (or invalid URI, because zip files don't
483 // permit ':'), and it will be ignored.
484 if( !sRelPath
.isEmpty() )
486 sal_Int32 nColPos
= sRelPath
.indexOf( ':' );
487 OSL_ENSURE( -1 == nColPos
,
488 "StreamRelPath contains ':', absolute URI?" );
492 OUString sTmp
= m_aExtPathPrefix
;
496 m_aExtPathPrefix
+= sTmp
;
497 nPos
= sRelPath
.indexOf( '/', nPos
+ 1 );
507 static sal_Int16
lcl_getUnit( const OUString
& rValue
)
509 if( rValue
.endsWithIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "cm" ) ) )
510 return util::MeasureUnit::CM
;
511 else if ( rValue
.endsWithIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "mm" ) ) )
512 return util::MeasureUnit::MM
;
514 return util::MeasureUnit::INCH
;
517 XMLMutableAttributeList
*XMLTransformerBase::ProcessAttrList(
518 Reference
< XAttributeList
>& rAttrList
, sal_uInt16 nActionMap
,
521 XMLMutableAttributeList
*pMutableAttrList
= 0;
522 XMLTransformerActions
*pActions
= GetUserDefinedActions( nActionMap
);
523 OSL_ENSURE( pActions
, "go no actions" );
526 sal_Int16 nAttrCount
= rAttrList
.is() ? rAttrList
->getLength() : 0;
527 for( sal_Int16 i
=0; i
< nAttrCount
; ++i
)
529 const OUString
& rAttrName
= rAttrList
->getNameByIndex( i
);
530 const OUString
& rAttrValue
= rAttrList
->getValueByIndex( i
);
532 sal_uInt16 nPrefix
= GetNamespaceMap().GetKeyByAttrName( rAttrName
,
535 XMLTransformerActions::key_type
aKey( nPrefix
, aLocalName
);
536 XMLTransformerActions::const_iterator aIter
=
537 pActions
->find( aKey
);
538 if( !(aIter
== pActions
->end() ) )
540 if( !pMutableAttrList
)
542 pMutableAttrList
= new XMLMutableAttributeList( rAttrList
,
544 rAttrList
= pMutableAttrList
;
547 sal_uInt32 nAction
= (*aIter
).second
.m_nActionType
;
548 sal_Bool bRename
= sal_False
;
551 case XML_ATACTION_RENAME
:
554 case XML_ATACTION_COPY
:
556 case XML_ATACTION_REMOVE
:
557 case XML_ATACTION_STYLE_DISPLAY_NAME
:
558 pMutableAttrList
->RemoveAttributeByIndex( i
);
562 case XML_ATACTION_RENAME_IN2INCH
:
564 case XML_ATACTION_IN2INCH
:
566 OUString
aAttrValue( rAttrValue
);
567 if( ReplaceSingleInWithInch( aAttrValue
) )
568 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
571 case XML_ATACTION_INS2INCHS
:
573 OUString
aAttrValue( rAttrValue
);
574 if( ReplaceInWithInch( aAttrValue
) )
575 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
578 case XML_ATACTION_RENAME_INCH2IN
:
580 case XML_ATACTION_INCH2IN
:
582 OUString
aAttrValue( rAttrValue
);
583 if( ReplaceSingleInchWithIn( aAttrValue
) )
584 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
587 case XML_ATACTION_INCHS2INS
:
589 OUString
aAttrValue( rAttrValue
);
590 if( ReplaceInchWithIn( aAttrValue
) )
591 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
594 case XML_ATACTION_TWIPS2IN
:
596 OUString
aAttrValue( rAttrValue
);
598 XMLTransformerBase::ReplaceSingleInchWithIn( aAttrValue
);
601 sal_Int16
const nDestUnit
= lcl_getUnit(aAttrValue
);
603 // convert twips value to inch
605 if (::sax::Converter::convertMeasure(nMeasure
,
606 aAttrValue
, util::MeasureUnit::MM_100TH
))
609 // #i13778#,#i36248# apply correct twip-to-1/100mm
610 nMeasure
= (sal_Int32
)( nMeasure
>= 0
611 ? ((nMeasure
*127+36)/72)
612 : ((nMeasure
*127-36)/72) );
614 rtl::OUStringBuffer aBuffer
;
615 ::sax::Converter::convertMeasure(aBuffer
,
616 nMeasure
, util::MeasureUnit::MM_100TH
,
618 aAttrValue
= aBuffer
.makeStringAndClear();
622 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
625 case XML_ATACTION_RENAME_DECODE_STYLE_NAME_REF
:
627 case XML_ATACTION_DECODE_STYLE_NAME
:
628 case XML_ATACTION_DECODE_STYLE_NAME_REF
:
630 OUString
aAttrValue( rAttrValue
);
631 if( DecodeStyleName(aAttrValue
) )
632 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
635 case XML_ATACTION_ENCODE_STYLE_NAME
:
637 OUString
aAttrValue( rAttrValue
);
638 if( EncodeStyleName(aAttrValue
) )
640 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
641 OUString
aNewAttrQName(
642 GetNamespaceMap().GetQNameByKey(
644 ::xmloff::token::GetXMLToken(
645 XML_DISPLAY_NAME
) ) );
646 pMutableAttrList
->AddAttribute( aNewAttrQName
,
651 case XML_ATACTION_RENAME_ENCODE_STYLE_NAME_REF
:
653 case XML_ATACTION_ENCODE_STYLE_NAME_REF
:
655 OUString
aAttrValue( rAttrValue
);
656 if( EncodeStyleName(aAttrValue
) )
657 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
660 case XML_ATACTION_RENAME_NEG_PERCENT
:
662 case XML_ATACTION_NEG_PERCENT
:
664 OUString
aAttrValue( rAttrValue
);
665 if( NegPercent( aAttrValue
) )
666 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
669 case XML_ATACTION_RENAME_ADD_NAMESPACE_PREFIX
:
671 case XML_ATACTION_ADD_NAMESPACE_PREFIX
:
673 OUString
aAttrValue( rAttrValue
);
674 sal_uInt16 nValPrefix
=
675 static_cast<sal_uInt16
>(
676 bRename
? (*aIter
).second
.m_nParam2
677 : (*aIter
).second
.m_nParam1
);
678 if( AddNamespacePrefix( aAttrValue
, nValPrefix
) )
679 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
682 case XML_ATACTION_ADD_APP_NAMESPACE_PREFIX
:
684 OUString
aAttrValue( rAttrValue
);
685 sal_uInt16 nValPrefix
=
686 static_cast<sal_uInt16
>((*aIter
).second
.m_nParam1
);
687 if( IsXMLToken( GetClass(), XML_SPREADSHEET
) )
688 nValPrefix
= XML_NAMESPACE_OOOC
;
689 else if( IsXMLToken( GetClass(), XML_TEXT
) )
690 nValPrefix
= XML_NAMESPACE_OOOW
;
691 if( AddNamespacePrefix( aAttrValue
, nValPrefix
) )
692 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
695 case XML_ATACTION_RENAME_REMOVE_NAMESPACE_PREFIX
:
697 case XML_ATACTION_REMOVE_NAMESPACE_PREFIX
:
699 OUString
aAttrValue( rAttrValue
);
700 sal_uInt16 nValPrefix
=
701 static_cast<sal_uInt16
>(
702 bRename
? (*aIter
).second
.m_nParam2
703 : (*aIter
).second
.m_nParam1
);
704 if( RemoveNamespacePrefix( aAttrValue
, nValPrefix
) )
705 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
708 case XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX
:
710 OUString
aAttrValue( rAttrValue
);
711 if( RemoveNamespacePrefix( aAttrValue
) )
712 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
715 case XML_ATACTION_URI_OOO
:
717 OUString
aAttrValue( rAttrValue
);
718 if( ConvertURIToOASIS( aAttrValue
,
719 static_cast< sal_Bool
>((*aIter
).second
.m_nParam1
)))
720 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
723 case XML_ATACTION_URI_OASIS
:
725 OUString
aAttrValue( rAttrValue
);
726 if( ConvertURIToOOo( aAttrValue
,
727 static_cast< sal_Bool
>((*aIter
).second
.m_nParam1
)))
728 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
731 case XML_ATACTION_RENAME_ATTRIBUTE
:
733 OUString
aAttrValue( rAttrValue
);
734 RenameAttributeValue(
736 (*aIter
).second
.m_nParam1
,
737 (*aIter
).second
.m_nParam2
,
738 (*aIter
).second
.m_nParam3
);
739 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
742 case XML_ATACTION_RNG2ISO_DATETIME
:
744 OUString
aAttrValue( rAttrValue
);
745 if( ConvertRNGDateTimeToISO( aAttrValue
))
746 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
749 case XML_ATACTION_RENAME_RNG2ISO_DATETIME
:
751 OUString
aAttrValue( rAttrValue
);
752 if( ConvertRNGDateTimeToISO( aAttrValue
))
753 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
757 case XML_ATACTION_IN2TWIPS
:
759 OUString
aAttrValue( rAttrValue
);
760 XMLTransformerBase::ReplaceSingleInWithInch( aAttrValue
);
764 sal_Int16
const nDestUnit
= lcl_getUnit(aAttrValue
);
766 // convert inch value to twips and export as faked inch
768 if (::sax::Converter::convertMeasure(nMeasure
,
769 aAttrValue
, util::MeasureUnit::MM_100TH
))
772 // #i13778#,#i36248#/ apply correct 1/100mm-to-twip conversion
773 nMeasure
= (sal_Int32
)( nMeasure
>= 0
774 ? ((nMeasure
*72+63)/127)
775 : ((nMeasure
*72-63)/127) );
777 OUStringBuffer aBuffer
;
778 ::sax::Converter::convertMeasure( aBuffer
,
779 nMeasure
, util::MeasureUnit::MM_100TH
,
781 aAttrValue
= aBuffer
.makeStringAndClear();
785 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
788 case XML_ATACTION_SVG_WIDTH_HEIGHT_OOO
:
790 OUString
aAttrValue( rAttrValue
);
791 ReplaceSingleInchWithIn( aAttrValue
);
793 sal_Int16
const nDestUnit
= lcl_getUnit( aAttrValue
);
796 if (::sax::Converter::convertMeasure(nMeasure
,
797 aAttrValue
, util::MeasureUnit::MM_100TH
))
802 else if( nMeasure
< 0 )
806 OUStringBuffer aBuffer
;
807 ::sax::Converter::convertMeasure(aBuffer
, nMeasure
,
808 util::MeasureUnit::MM_100TH
, nDestUnit
);
809 aAttrValue
= aBuffer
.makeStringAndClear();
812 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
815 case XML_ATACTION_SVG_WIDTH_HEIGHT_OASIS
:
817 OUString
aAttrValue( rAttrValue
);
818 ReplaceSingleInWithInch( aAttrValue
);
820 sal_Int16
const nDestUnit
= lcl_getUnit( aAttrValue
);
823 if (::sax::Converter::convertMeasure(nMeasure
,
824 aAttrValue
, util::MeasureUnit::MM_100TH
))
829 else if( nMeasure
< 0 )
833 OUStringBuffer aBuffer
;
834 ::sax::Converter::convertMeasure(aBuffer
, nMeasure
,
835 util::MeasureUnit::MM_100TH
, nDestUnit
);
836 aAttrValue
= aBuffer
.makeStringAndClear();
839 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
842 case XML_ATACTION_DECODE_ID
:
846 const sal_Int32 nLen
= rAttrValue
.getLength();
847 OUStringBuffer aBuffer
;
850 for( pos
= 0; pos
< nLen
; pos
++ )
852 sal_Unicode c
= rAttrValue
[pos
];
853 if( (c
>= '0') && (c
<= '9') )
856 aBuffer
.append( (sal_Int32
)c
);
859 pMutableAttrList
->SetValueByIndex( i
, aBuffer
.makeStringAndClear() );
862 // #i50322# - special handling for the
863 // transparency of writer background graphics.
864 case XML_ATACTION_WRITER_BACK_GRAPHIC_TRANSPARENCY
:
866 // determine, if it's the transparency of a document style
867 XMLTransformerContext
* pFirstContext
= (*m_pContexts
)[0].get();
868 OUString aFirstContextLocalName
;
869 /* sal_uInt16 nFirstContextPrefix = */
870 GetNamespaceMap().GetKeyByAttrName( pFirstContext
->GetQName(),
871 &aFirstContextLocalName
);
872 bool bIsDocumentStyle(
873 ::xmloff::token::IsXMLToken( aFirstContextLocalName
,
874 XML_DOCUMENT_STYLES
) );
875 // no conversion of transparency value for document
876 // styles, because former OpenOffice.org version writes
877 // writes always a transparency value of 100% and doesn't
878 // read the value. Thus, it's intepreted as 0%
879 if ( !bIsDocumentStyle
)
881 OUString
aAttrValue( rAttrValue
);
882 NegPercent(aAttrValue
);
883 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
888 case XML_ATACTION_SHAPEID
:
890 OUString
sNewValue( "shape" );
891 sNewValue
+= rAttrValue
;
892 pMutableAttrList
->SetValueByIndex( i
, sNewValue
);
897 OSL_ENSURE( !this, "unknown action" );
903 OUString
aNewAttrQName(
904 GetNamespaceMap().GetQNameByKey(
905 (*aIter
).second
.GetQNamePrefixFromParam1(),
906 ::xmloff::token::GetXMLToken(
907 (*aIter
).second
.GetQNameTokenFromParam1()) ) );
908 pMutableAttrList
->RenameAttributeByIndex( i
,
915 return pMutableAttrList
;
918 sal_Bool
XMLTransformerBase::ReplaceSingleInchWithIn( OUString
& rValue
)
920 sal_Bool bRet
= sal_False
;
921 sal_Int32 nPos
= rValue
.getLength();
922 while( nPos
&& rValue
[nPos
-1] <= ' ' )
925 ('c'==rValue
[nPos
-2] || 'C'==rValue
[nPos
-2]) &&
926 ('h'==rValue
[nPos
-1] || 'H'==rValue
[nPos
-1]) )
928 rValue
=rValue
.copy( 0, nPos
-2 );
935 sal_Bool
XMLTransformerBase::ReplaceInchWithIn( OUString
& rValue
)
937 sal_Bool bRet
= sal_False
;
939 while( nPos
< rValue
.getLength()-3 )
941 sal_Unicode c
= rValue
[nPos
];
942 if( 'i'==c
|| 'I'==c
)
945 if( (c
>= '0' && c
<= '9') || '.' == c
)
948 if( 'n'==c
|| 'N'==c
)
951 if( 'c'==c
|| 'C'==c
)
954 if( 'h'==c
|| 'H'==c
)
956 rValue
= rValue
.replaceAt( nPos
,
957 4, GetXMLToken(XML_UNIT_INCH
) );
972 sal_Bool
XMLTransformerBase::ReplaceSingleInWithInch( OUString
& rValue
)
974 sal_Bool bRet
= sal_False
;
976 sal_Int32 nPos
= rValue
.getLength();
977 while( nPos
&& rValue
[nPos
-1] <= ' ' )
980 ('i'==rValue
[nPos
-2] ||
981 'I'==rValue
[nPos
-2]) &&
982 ('n'==rValue
[nPos
-1] ||
983 'N'==rValue
[nPos
-1]) )
986 rValue
= rValue
.replaceAt( nPos
, rValue
.getLength() - nPos
,
987 GetXMLToken(XML_INCH
) );
994 sal_Bool
XMLTransformerBase::ReplaceInWithInch( OUString
& rValue
)
996 sal_Bool bRet
= sal_False
;
998 while( nPos
< rValue
.getLength()-1 )
1000 sal_Unicode c
= rValue
[nPos
];
1001 if( 'i'==c
|| 'I'==c
)
1004 if( (c
>= '0' && c
<= '9') || '.' == c
)
1007 if( 'n'==c
|| 'N'==c
)
1009 rValue
= rValue
.replaceAt( nPos
,
1010 2, GetXMLToken(XML_INCH
) );
1023 sal_Bool
XMLTransformerBase::EncodeStyleName( OUString
& rName
) const
1025 static sal_Char aHexTab
[] = "0123456789abcdef";
1027 sal_Bool bEncoded
= sal_False
;
1029 sal_Int32 nLen
= rName
.getLength();
1030 OUStringBuffer
aBuffer( nLen
);
1032 for( sal_Int32 i
= 0; i
< nLen
; i
++ )
1034 sal_Unicode c
= rName
[i
];
1035 sal_Bool bValidChar
= sal_False
;
1039 (c
>= 0x0041 && c
<= 0x005a) ||
1040 (c
>= 0x0061 && c
<= 0x007a) ||
1041 (c
>= 0x00c0 && c
<= 0x00d6) ||
1042 (c
>= 0x00d8 && c
<= 0x00f6) ||
1043 (c
>= 0x00f8 && c
<= 0x00ff) ||
1044 ( i
> 0 && ( (c
>= 0x0030 && c
<= 0x0039) ||
1045 c
== 0x00b7 || c
== '-' || c
== '.') );
1049 if( (c
>= 0xf900U
&& c
<= 0xfffeU
) ||
1050 (c
>= 0x20ddU
&& c
<= 0x20e0U
))
1052 bValidChar
= sal_False
;
1054 else if( (c
>= 0x02bbU
&& c
<= 0x02c1U
) || c
== 0x0559 ||
1055 c
== 0x06e5 || c
== 0x06e6 )
1057 bValidChar
= sal_True
;
1059 else if( c
== 0x0387 )
1065 if( !xCharClass
.is() )
1067 Reference
< XMultiServiceFactory
> xFactory
=
1068 comphelper::getProcessServiceFactory();
1073 const_cast < XMLTransformerBase
* >(this)
1075 Reference
< XCharacterClassification
>(
1076 xFactory
->createInstance(
1078 "com.sun.star.i18n.CharacterClassification_Unicode") ),
1081 OSL_ENSURE( xCharClass
.is(),
1082 "can't instantiate character clossification component" );
1084 catch( com::sun::star::uno::Exception
& )
1089 if( xCharClass
.is() )
1091 sal_Int16 nType
= xCharClass
->getType( rName
, i
);
1095 case UnicodeType::UPPERCASE_LETTER
: // Lu
1096 case UnicodeType::LOWERCASE_LETTER
: // Ll
1097 case UnicodeType::TITLECASE_LETTER
: // Lt
1098 case UnicodeType::OTHER_LETTER
: // Lo
1099 case UnicodeType::LETTER_NUMBER
: // Nl
1100 bValidChar
= sal_True
;
1102 case UnicodeType::NON_SPACING_MARK
: // Ms
1103 case UnicodeType::ENCLOSING_MARK
: // Me
1104 case UnicodeType::COMBINING_SPACING_MARK
: //Mc
1105 case UnicodeType::MODIFIER_LETTER
: // Lm
1106 case UnicodeType::DECIMAL_DIGIT_NUMBER
: // Nd
1115 aBuffer
.append( c
);
1119 aBuffer
.append( static_cast< sal_Unicode
>( '_' ) );
1121 aBuffer
.append( static_cast< sal_Unicode
>(
1122 aHexTab
[ (c
>> 12) & 0x0f ] ) );
1124 aBuffer
.append( static_cast< sal_Unicode
>(
1125 aHexTab
[ (c
>> 8) & 0x0f ] ) );
1127 aBuffer
.append( static_cast< sal_Unicode
>(
1128 aHexTab
[ (c
>> 4) & 0x0f ] ) );
1129 aBuffer
.append( static_cast< sal_Unicode
>(
1130 aHexTab
[ c
& 0x0f ] ) );
1131 aBuffer
.append( static_cast< sal_Unicode
>( '_' ) );
1132 bEncoded
= sal_True
;
1136 if( aBuffer
.getLength() > (1<<15)-1 )
1137 bEncoded
= sal_False
;
1140 rName
= aBuffer
.makeStringAndClear();
1144 sal_Bool
XMLTransformerBase::DecodeStyleName( OUString
& rName
)
1146 sal_Bool bEncoded
= sal_False
;
1148 sal_Int32 nLen
= rName
.getLength();
1149 OUStringBuffer
aBuffer( nLen
);
1151 sal_Bool bWithinHex
= sal_False
;
1152 sal_Unicode cEnc
= 0;
1153 for( sal_Int32 i
= 0; i
< nLen
; i
++ )
1155 sal_Unicode c
= rName
[i
];
1160 aBuffer
.append( cEnc
);
1165 bEncoded
= sal_True
;
1167 bWithinHex
= !bWithinHex
;
1169 else if( bWithinHex
)
1172 if( c
>= '0' && c
<= '9' )
1176 else if( c
>= 'a' && c
<= 'f' )
1178 cDigit
= c
- 'a' + 10;
1180 else if( c
>= 'A' && c
<= 'F' )
1182 cDigit
= c
- 'A' + 10;
1187 bEncoded
= sal_False
;
1190 cEnc
= (cEnc
<< 4) + cDigit
;
1194 aBuffer
.append( c
);
1199 rName
= aBuffer
.makeStringAndClear();
1203 sal_Bool
XMLTransformerBase::NegPercent( OUString
& rValue
)
1205 sal_Bool bRet
= sal_False
;
1206 sal_Bool bNeg
= sal_False
;
1210 sal_Int32 nLen
= rValue
.getLength();
1213 while( nPos
< nLen
&& sal_Unicode(' ') == rValue
[nPos
] )
1216 if( nPos
< nLen
&& sal_Unicode('-') == rValue
[nPos
] )
1223 while( nPos
< nLen
&&
1224 sal_Unicode('0') <= rValue
[nPos
] &&
1225 sal_Unicode('9') >= rValue
[nPos
] )
1227 // TODO: check overflow!
1229 nVal
+= (rValue
[nPos
] - sal_Unicode('0'));
1233 if( nPos
< nLen
&& sal_Unicode('.') == rValue
[nPos
] )
1237 while( nPos
< nLen
&&
1238 sal_Unicode('0') <= rValue
[nPos
] &&
1239 sal_Unicode('9') >= rValue
[nPos
] )
1241 // TODO: check overflow!
1243 nVal
+= ( static_cast<double>(rValue
[nPos
] - sal_Unicode('0')) / nDiv
);
1249 while( nPos
< nLen
&& sal_Unicode(' ') == rValue
[nPos
] )
1252 if( nPos
< nLen
&& sal_Unicode('%') == rValue
[nPos
] )
1258 sal_Int32 nIntVal
= 100 - static_cast<sal_Int32
>( nVal
);
1260 OUStringBuffer aNewValBuffer
;
1261 aNewValBuffer
.append( nIntVal
);
1262 aNewValBuffer
.append( sal_Unicode('%' ) );
1264 rValue
= aNewValBuffer
.makeStringAndClear();
1271 sal_Bool
XMLTransformerBase::AddNamespacePrefix( ::rtl::OUString
& rName
,
1272 sal_uInt16 nPrefix
) const
1274 rName
= GetNamespaceMap().GetQNameByKey( nPrefix
, rName
, sal_False
);
1278 sal_Bool
XMLTransformerBase::RemoveNamespacePrefix( ::rtl::OUString
& rName
,
1279 sal_uInt16 nPrefixOnly
) const
1281 OUString aLocalName
;
1282 sal_uInt16 nPrefix
=
1283 GetNamespaceMap()._GetKeyByAttrName( rName
, &aLocalName
, sal_False
);
1284 sal_Bool bRet
= XML_NAMESPACE_UNKNOWN
!= nPrefix
&&
1285 (USHRT_MAX
== nPrefixOnly
|| nPrefix
== nPrefixOnly
);
1292 sal_Bool
XMLTransformerBase::ConvertURIToOASIS( ::rtl::OUString
& rURI
,
1293 sal_Bool bSupportPackage
) const
1295 sal_Bool bRet
= sal_False
;
1296 if( !m_aExtPathPrefix
.isEmpty() && !rURI
.isEmpty() )
1298 sal_Bool bRel
= sal_False
;
1303 // for package URIs, the '#' has to be removed
1304 if( bSupportPackage
)
1306 rURI
= rURI
.copy( 1 );
1311 // no rel path; nothing to do
1314 // a rel path; to keep URI simple, remove './', if there
1316 if( rURI
.getLength() > 1 && '/' == rURI
[1] )
1318 rURI
= rURI
.copy( 2 );
1323 // check for a RFC2396 schema
1327 sal_Int32 nLen
= rURI
.getLength();
1328 while( nPos
< nLen
)
1330 switch( rURI
[nPos
] )
1333 // a relative path segement
1334 nPos
= nLen
; // leave loop
1339 nPos
= nLen
; // leave loop
1342 // we don't care about any other characters
1352 OUString
sTmp( m_aExtPathPrefix
);
1362 sal_Bool
XMLTransformerBase::ConvertURIToOOo( ::rtl::OUString
& rURI
,
1363 sal_Bool bSupportPackage
) const
1365 sal_Bool bRet
= sal_False
;
1366 if( !rURI
.isEmpty() )
1368 sal_Bool bPackage
= sal_False
;
1372 // no rel path; nothing to to
1376 if( 0 == rURI
.compareTo( m_aExtPathPrefix
,
1377 m_aExtPathPrefix
.getLength() ) )
1379 // an external URI; remove '../'
1380 rURI
= rURI
.copy( m_aExtPathPrefix
.getLength() );
1385 bPackage
= sal_True
;
1389 // check for a RFC2396 schema
1391 bPackage
= sal_True
;
1393 sal_Int32 nLen
= rURI
.getLength();
1394 while( nPos
< nLen
)
1396 switch( rURI
[nPos
] )
1399 // a relative path segement within the package
1400 nPos
= nLen
; // leave loop
1404 bPackage
= sal_False
;
1405 nPos
= nLen
; // leave loop
1408 // we don't care about any other characters
1416 if( bPackage
&& bSupportPackage
)
1418 OUString
sTmp( OUString::valueOf( sal_Unicode( '#' ) ) );
1419 if( 0 == rURI
.compareToAscii( "./", 2 ) )
1420 rURI
= rURI
.copy( 2 );
1430 sal_Bool
XMLTransformerBase::RenameAttributeValue(
1431 OUString
& rOutAttributeValue
,
1436 return ( lcl_ConvertAttr( rOutAttributeValue
, nParam1
) ||
1437 lcl_ConvertAttr( rOutAttributeValue
, nParam2
) ||
1438 lcl_ConvertAttr( rOutAttributeValue
, nParam3
) );
1442 bool XMLTransformerBase::ConvertRNGDateTimeToISO( ::rtl::OUString
& rDateTime
)
1444 if( !rDateTime
.isEmpty() &&
1445 rDateTime
.indexOf( sal_Unicode('.')) != -1 )
1447 rDateTime
= rDateTime
.replace( sal_Unicode('.'), sal_Unicode(','));
1454 XMLTokenEnum
XMLTransformerBase::GetToken( const OUString
& rStr
) const
1456 XMLTransformerTokenMap::const_iterator aIter
=
1457 m_pTokenMap
->find( rStr
);
1458 if( aIter
== m_pTokenMap
->end() )
1459 return XML_TOKEN_END
;
1461 return (*aIter
).second
;
1466 const XMLTransformerContext
*XMLTransformerBase::GetCurrentContext() const
1468 OSL_ENSURE( !m_pContexts
->empty(), "empty stack" );
1471 return m_pContexts
->empty() ? 0 : m_pContexts
->back().get();
1474 const XMLTransformerContext
*XMLTransformerBase::GetAncestorContext(
1475 sal_uInt32 n
) const
1477 XMLTransformerContextVector::size_type nSize
=
1478 m_pContexts
->size();
1479 XMLTransformerContextVector::size_type nPos
=
1480 static_cast<XMLTransformerContextVector::size_type
>( n
);
1482 OSL_ENSURE( nSize
>nPos
+2 , "invalid context" );
1484 return nSize
> nPos
+2 ? (*m_pContexts
)[nSize
-(nPos
+2)].get() : 0;
1487 bool XMLTransformerBase::isWriter() const
1489 Reference
< XServiceInfo
> xSI( mxModel
, UNO_QUERY
);
1491 ( xSI
->supportsService( OUString( "com.sun.star.text.TextDocument" ) ) ||
1492 xSI
->supportsService( OUString( "com.sun.star.text.WebDocument" ) ) ||
1493 xSI
->supportsService( OUString( "com.sun.star.text.GlobalDocument" ) ) );
1496 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */