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 .
20 #include <rtl/ref.hxx>
21 #include <rtl/ustrbuf.hxx>
22 #include <osl/diagnose.h>
23 #include <com/sun/star/i18n/CharacterClassification.hpp>
24 #include <com/sun/star/i18n/UnicodeType.hpp>
25 #include <com/sun/star/util/MeasureUnit.hpp>
26 #include <sax/tools/converter.hxx>
27 #include <comphelper/processfactory.hxx>
28 #include <xmloff/nmspmap.hxx>
29 #include <xmloff/xmlnmspe.hxx>
30 #include "IgnoreTContext.hxx"
31 #include "RenameElemTContext.hxx"
32 #include "ProcAttrTContext.hxx"
33 #include "ProcAddAttrTContext.hxx"
34 #include "MergeElemTContext.hxx"
35 #include "CreateElemTContext.hxx"
36 #include "MutableAttrList.hxx"
37 #include "TransformerActions.hxx"
38 #include "ElemTransformerAction.hxx"
39 #include "PropertyActionsOOo.hxx"
40 #include "TransformerTokenMap.hxx"
42 #include "TransformerBase.hxx"
43 #include "TContextVector.hxx"
45 using namespace ::osl
;
46 using namespace ::xmloff::token
;
47 using namespace ::com::sun::star
;
48 using namespace ::com::sun::star::uno
;
49 using namespace ::com::sun::star::beans
;
50 using namespace ::com::sun::star::lang
;
51 using namespace ::com::sun::star::i18n
;
52 using namespace ::com::sun::star::xml::sax
;
56 bool lcl_ConvertAttr( OUString
& rOutAttribute
, sal_Int32 nParam
)
59 enum XMLTokenEnum eTokenToRename
=
60 static_cast< enum XMLTokenEnum
>( nParam
& 0xffff );
61 if( eTokenToRename
!= XML_TOKEN_INVALID
&&
62 IsXMLToken( rOutAttribute
, eTokenToRename
))
64 enum XMLTokenEnum eReplacementToken
=
65 static_cast< enum XMLTokenEnum
>( nParam
>> 16 );
66 rOutAttribute
= GetXMLToken( eReplacementToken
);
71 } // anonymous namespace
73 XMLTransformerContext
*XMLTransformerBase::CreateContext( sal_uInt16 nPrefix
,
74 const OUString
& rLocalName
, const OUString
& rQName
)
76 XMLTransformerActions::key_type
aKey( nPrefix
, rLocalName
);
77 XMLTransformerActions::const_iterator aIter
=
78 GetElemActions().find( aKey
);
80 if( !(aIter
== GetElemActions().end()) )
82 sal_uInt32 nActionType
= (*aIter
).second
.m_nActionType
;
83 if( (nActionType
& XML_ETACTION_USER_DEFINED
) != 0 )
85 XMLTransformerContext
*pContext
=
86 CreateUserDefinedContext( (*aIter
).second
,
88 OSL_ENSURE( pContext
&& !pContext
->IsPersistent(),
89 "unknown or not persistent action" );
95 case XML_ETACTION_COPY_CONTENT
:
96 return new XMLIgnoreTransformerContext( *this, rQName
, false,
98 case XML_ETACTION_COPY
:
99 return new XMLTransformerContext( *this, rQName
);
100 case XML_ETACTION_RENAME_ELEM
:
101 return new XMLRenameElemTransformerContext( *this, rQName
,
102 (*aIter
).second
.GetQNamePrefixFromParam1(),
103 (*aIter
).second
.GetQNameTokenFromParam1() );
104 case XML_ETACTION_RENAME_ELEM_ADD_ATTR
:
105 return new XMLRenameElemTransformerContext( *this, rQName
,
106 (*aIter
).second
.GetQNamePrefixFromParam1(),
107 (*aIter
).second
.GetQNameTokenFromParam1(),
108 (*aIter
).second
.GetQNamePrefixFromParam2(),
109 (*aIter
).second
.GetQNameTokenFromParam2(),
110 static_cast< XMLTokenEnum
>( (*aIter
).second
.m_nParam3
) );
111 case XML_ETACTION_RENAME_ELEM_PROC_ATTRS
:
112 return new XMLProcAttrTransformerContext( *this, rQName
,
113 (*aIter
).second
.GetQNamePrefixFromParam1(),
114 (*aIter
).second
.GetQNameTokenFromParam1(),
115 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam2
) );
116 case XML_ETACTION_RENAME_ELEM_ADD_PROC_ATTR
:
117 return new XMLProcAddAttrTransformerContext( *this, rQName
,
118 (*aIter
).second
.GetQNamePrefixFromParam1(),
119 (*aIter
).second
.GetQNameTokenFromParam1(),
120 static_cast< sal_uInt16
>(
121 (*aIter
).second
.m_nParam3
>> 16 ),
122 (*aIter
).second
.GetQNamePrefixFromParam2(),
123 (*aIter
).second
.GetQNameTokenFromParam2(),
124 static_cast< XMLTokenEnum
>(
125 (*aIter
).second
.m_nParam3
& 0xffff ) );
126 case XML_ETACTION_RENAME_ELEM_COND
:
128 const XMLTransformerContext
*pCurrent
= GetCurrentContext();
129 if( pCurrent
->HasQName(
130 (*aIter
).second
.GetQNamePrefixFromParam2(),
131 (*aIter
).second
.GetQNameTokenFromParam2() ) )
132 return new XMLRenameElemTransformerContext( *this, rQName
,
133 (*aIter
).second
.GetQNamePrefixFromParam1(),
134 (*aIter
).second
.GetQNameTokenFromParam1() );
137 case XML_ETACTION_RENAME_ELEM_PROC_ATTRS_COND
:
139 const XMLTransformerContext
*pCurrent
= GetCurrentContext();
140 if( pCurrent
->HasQName(
141 (*aIter
).second
.GetQNamePrefixFromParam3(),
142 (*aIter
).second
.GetQNameTokenFromParam3() ) )
143 return new XMLProcAttrTransformerContext( *this, rQName
,
144 (*aIter
).second
.GetQNamePrefixFromParam1(),
145 (*aIter
).second
.GetQNameTokenFromParam1(),
146 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam2
) );
148 return new XMLProcAttrTransformerContext( *this, rQName
,
149 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam2
) );
151 case XML_ETACTION_PROC_ATTRS
:
152 return new XMLProcAttrTransformerContext( *this, rQName
,
153 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam1
) );
154 case XML_ETACTION_PROC_ATTRS_COND
:
156 const XMLTransformerContext
*pCurrent
= GetCurrentContext();
157 if( pCurrent
->HasQName(
158 (*aIter
).second
.GetQNamePrefixFromParam1(),
159 (*aIter
).second
.GetQNameTokenFromParam1() ) )
160 return new XMLProcAttrTransformerContext( *this, rQName
,
161 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam2
) );
164 case XML_ETACTION_MOVE_ATTRS_TO_ELEMS
:
165 return new XMLCreateElemTransformerContext( *this, rQName
,
166 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam1
) );
167 case XML_ETACTION_MOVE_ELEMS_TO_ATTRS
:
168 return new XMLMergeElemTransformerContext( *this, rQName
,
169 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam1
) );
171 OSL_ENSURE( false, "unknown action" );
176 // default is copying
177 return new XMLTransformerContext( *this, rQName
);
180 XMLTransformerActions
*XMLTransformerBase::GetUserDefinedActions( sal_uInt16
)
185 XMLTransformerBase::XMLTransformerBase( XMLTransformerActionInit
*pInit
,
186 ::xmloff::token::XMLTokenEnum
*pTKMapInit
)
188 m_pNamespaceMap( new SvXMLNamespaceMap
),
189 m_pReplaceNamespaceMap( new SvXMLNamespaceMap
),
190 m_pContexts( new XMLTransformerContextVector
),
191 m_pElemActions( new XMLTransformerActions( pInit
) ),
192 m_pTokenMap( new XMLTransformerTokenMap( pTKMapInit
) )
194 GetNamespaceMap().Add( GetXMLToken(XML_NP_XLINK
), GetXMLToken(XML_N_XLINK
), XML_NAMESPACE_XLINK
);
195 GetNamespaceMap().Add( GetXMLToken(XML_NP_DC
), GetXMLToken(XML_N_DC
), XML_NAMESPACE_DC
);
196 GetNamespaceMap().Add( GetXMLToken(XML_NP_MATH
), GetXMLToken(XML_N_MATH
), XML_NAMESPACE_MATH
);
197 GetNamespaceMap().Add( GetXMLToken(XML_NP_OOO
), GetXMLToken(XML_N_OOO
), XML_NAMESPACE_OOO
);
198 GetNamespaceMap().Add( GetXMLToken(XML_NP_DOM
), GetXMLToken(XML_N_DOM
), XML_NAMESPACE_DOM
);
199 GetNamespaceMap().Add( GetXMLToken(XML_NP_OOOW
), GetXMLToken(XML_N_OOOW
), XML_NAMESPACE_OOOW
);
200 GetNamespaceMap().Add( GetXMLToken(XML_NP_OOOC
), GetXMLToken(XML_N_OOOC
), XML_NAMESPACE_OOOC
);
203 XMLTransformerBase::~XMLTransformerBase() throw ()
205 delete m_pNamespaceMap
;
206 delete m_pReplaceNamespaceMap
;
208 delete m_pElemActions
;
212 void SAL_CALL
XMLTransformerBase::startDocument()
213 throw( SAXException
, RuntimeException
, std::exception
)
215 m_xHandler
->startDocument();
218 void SAL_CALL
XMLTransformerBase::endDocument()
219 throw( SAXException
, RuntimeException
, std::exception
)
221 m_xHandler
->endDocument();
224 void SAL_CALL
XMLTransformerBase::startElement( const OUString
& rName
,
225 const Reference
< XAttributeList
>& rAttrList
)
226 throw(SAXException
, RuntimeException
, std::exception
)
228 SvXMLNamespaceMap
*pRewindMap
= 0;
230 bool bRect
= rName
== "presentation:show-shape";
233 // Process namespace attributes. This must happen before creating the
234 // context, because namespace decaration apply to the element name itself.
235 XMLMutableAttributeList
*pMutableAttrList
= 0;
236 Reference
< XAttributeList
> xAttrList( rAttrList
);
237 sal_Int16 nAttrCount
= xAttrList
.is() ? xAttrList
->getLength() : 0;
238 for( sal_Int16 i
=0; i
< nAttrCount
; i
++ )
240 const OUString
& rAttrName
= xAttrList
->getNameByIndex( i
);
241 if( ( rAttrName
.getLength() >= 5 ) &&
242 ( rAttrName
.startsWith( GetXMLToken(XML_XMLNS
) ) ) &&
243 ( rAttrName
.getLength() == 5 || ':' == rAttrName
[5] ) )
247 pRewindMap
= m_pNamespaceMap
;
248 m_pNamespaceMap
= new SvXMLNamespaceMap( *m_pNamespaceMap
);
250 const OUString
& rAttrValue
= xAttrList
->getValueByIndex( i
);
252 OUString
aPrefix( ( rAttrName
.getLength() == 5 )
254 : rAttrName
.copy( 6 ) );
255 // Add namespace, but only if it is known.
256 sal_uInt16 nKey
= m_pNamespaceMap
->AddIfKnown( aPrefix
, rAttrValue
);
257 // If namespace is unknown, try to match a name with similar
259 if( XML_NAMESPACE_UNKNOWN
== nKey
)
261 OUString
aTestName( rAttrValue
);
262 if( SvXMLNamespaceMap::NormalizeOasisURN( aTestName
) )
263 nKey
= m_pNamespaceMap
->AddIfKnown( aPrefix
, aTestName
);
265 // If that namespace is not known, too, add it as unknown
266 if( XML_NAMESPACE_UNKNOWN
== nKey
)
267 nKey
= m_pNamespaceMap
->Add( aPrefix
, rAttrValue
);
269 const OUString
& rRepName
= m_pReplaceNamespaceMap
->GetNameByKey( nKey
);
270 if( !rRepName
.isEmpty() )
272 if( !pMutableAttrList
)
274 pMutableAttrList
= new XMLMutableAttributeList( xAttrList
);
275 xAttrList
= pMutableAttrList
;
278 pMutableAttrList
->SetValueByIndex( i
, rRepName
);
283 // Get element's namespace and local name.
286 m_pNamespaceMap
->GetKeyByAttrName( rName
, &aLocalName
);
288 // If there are contexts already, call a CreateChildContext at the topmost
289 // context. Otherwise, create a default context.
290 ::rtl::Reference
< XMLTransformerContext
> xContext
;
291 if( !m_pContexts
->empty() )
293 xContext
= m_pContexts
->back()->CreateChildContext( nPrefix
,
300 xContext
= CreateContext( nPrefix
, aLocalName
, rName
);
303 OSL_ENSURE( xContext
.is(), "XMLTransformerBase::startElement: missing context" );
305 xContext
= new XMLTransformerContext( *this, rName
);
307 // Remember old namespace map.
309 xContext
->SetRewindMap( pRewindMap
);
311 // Push context on stack.
312 m_pContexts
->push_back( xContext
);
314 // Call a startElement at the new context.
315 xContext
->StartElement( xAttrList
);
318 void SAL_CALL
XMLTransformerBase::endElement( const OUString
&
319 #if OSL_DEBUG_LEVEL > 0
323 throw(SAXException
, RuntimeException
, std::exception
)
325 if( !m_pContexts
->empty() )
327 // Get topmost context
328 ::rtl::Reference
< XMLTransformerContext
> xContext
= m_pContexts
->back();
330 #if OSL_DEBUG_LEVEL > 0
331 OSL_ENSURE( xContext
->GetQName() == rName
,
332 "XMLTransformerBase::endElement: popped context has wrong lname" );
335 // Call a EndElement at the current context.
336 xContext
->EndElement();
338 // and remove it from the stack.
339 m_pContexts
->pop_back();
341 // Get a namespace map to rewind.
342 SvXMLNamespaceMap
*pRewindMap
= xContext
->GetRewindMap();
344 // Delete the current context.
347 // Rewind a namespace map.
350 delete m_pNamespaceMap
;
351 m_pNamespaceMap
= pRewindMap
;
356 void SAL_CALL
XMLTransformerBase::characters( const OUString
& rChars
)
357 throw(SAXException
, RuntimeException
, std::exception
)
359 if( !m_pContexts
->empty() )
361 m_pContexts
->back()->Characters( rChars
);
365 void SAL_CALL
XMLTransformerBase::ignorableWhitespace( const OUString
& rWhitespaces
)
366 throw(SAXException
, RuntimeException
, std::exception
)
368 m_xHandler
->ignorableWhitespace( rWhitespaces
);
371 void SAL_CALL
XMLTransformerBase::processingInstruction( const OUString
& rTarget
,
372 const OUString
& rData
)
373 throw(SAXException
, RuntimeException
, std::exception
)
375 m_xHandler
->processingInstruction( rTarget
, rData
);
378 void SAL_CALL
XMLTransformerBase::setDocumentLocator( const Reference
< XLocator
>& rLocator
)
379 throw(SAXException
, RuntimeException
, std::exception
)
381 m_xLocator
= rLocator
;
384 // XExtendedDocumentHandler
385 void SAL_CALL
XMLTransformerBase::startCDATA() throw(SAXException
, RuntimeException
, std::exception
)
387 if( m_xExtHandler
.is() )
388 m_xExtHandler
->startCDATA();
391 void SAL_CALL
XMLTransformerBase::endCDATA() throw(RuntimeException
, std::exception
)
393 if( m_xExtHandler
.is() )
394 m_xExtHandler
->endCDATA();
397 void SAL_CALL
XMLTransformerBase::comment( const OUString
& rComment
)
398 throw(SAXException
, RuntimeException
, std::exception
)
400 if( m_xExtHandler
.is() )
401 m_xExtHandler
->comment( rComment
);
404 void SAL_CALL
XMLTransformerBase::allowLineBreak()
405 throw(SAXException
, RuntimeException
, std::exception
)
407 if( m_xExtHandler
.is() )
408 m_xExtHandler
->allowLineBreak();
411 void SAL_CALL
XMLTransformerBase::unknown( const OUString
& rString
)
412 throw(SAXException
, RuntimeException
, std::exception
)
414 if( m_xExtHandler
.is() )
415 m_xExtHandler
->unknown( rString
);
419 void SAL_CALL
XMLTransformerBase::initialize( const Sequence
< Any
>& aArguments
)
420 throw(Exception
, RuntimeException
, std::exception
)
422 const sal_Int32 nAnyCount
= aArguments
.getLength();
423 const Any
* pAny
= aArguments
.getConstArray();
425 for( sal_Int32 nIndex
= 0; nIndex
< nAnyCount
; nIndex
++, pAny
++ )
427 // use isAssignableFrom instead of comparing the types to
428 // allow XExtendedDocumentHandler instead of XDocumentHandler (used in
429 // writeOasis2OOoLibraryElement in sfx2).
430 // The Any shift operator can't be used to query the type because it
431 // uses queryInterface, and the model also has a XPropertySet interface.
434 if( cppu::UnoType
<XDocumentHandler
>::get().isAssignableFrom( pAny
->getValueType() ) )
435 m_xHandler
.set( *pAny
, UNO_QUERY
);
437 // property set to transport data across
438 if( cppu::UnoType
<XPropertySet
>::get().isAssignableFrom( pAny
->getValueType() ) )
439 m_xPropSet
.set( *pAny
, UNO_QUERY
);
442 if( cppu::UnoType
<com::sun::star::frame::XModel
>::get().isAssignableFrom( pAny
->getValueType() ) )
443 mxModel
.set( *pAny
, UNO_QUERY
);
446 if( m_xPropSet
.is() )
449 OUString sRelPath
, sName
;
450 Reference
< XPropertySetInfo
> xPropSetInfo
=
451 m_xPropSet
->getPropertySetInfo();
452 OUString
sPropName( "StreamRelPath" );
453 if( xPropSetInfo
->hasPropertyByName(sPropName
) )
455 aAny
= m_xPropSet
->getPropertyValue(sPropName
);
458 sPropName
= "StreamName";
459 if( xPropSetInfo
->hasPropertyByName(sPropName
) )
461 aAny
= m_xPropSet
->getPropertyValue(sPropName
);
464 if( !sName
.isEmpty() )
466 m_aExtPathPrefix
= "../";
468 // If there is a rel path within a package, then append
469 // additional '../'. If the rel path contains an ':', then it is
470 // an absolute URI (or invalid URI, because zip files don't
471 // permit ':'), and it will be ignored.
472 if( !sRelPath
.isEmpty() )
474 sal_Int32 nColPos
= sRelPath
.indexOf( ':' );
475 OSL_ENSURE( -1 == nColPos
,
476 "StreamRelPath contains ':', absolute URI?" );
480 OUString sTmp
= m_aExtPathPrefix
;
484 m_aExtPathPrefix
+= sTmp
;
485 nPos
= sRelPath
.indexOf( '/', nPos
+ 1 );
494 assert(m_xHandler
.is()); // can't do anything without that
497 static sal_Int16
lcl_getUnit( const OUString
& rValue
)
499 if( rValue
.endsWithIgnoreAsciiCase( "cm" ) )
500 return util::MeasureUnit::CM
;
501 else if ( rValue
.endsWithIgnoreAsciiCase( "mm" ) )
502 return util::MeasureUnit::MM
;
504 return util::MeasureUnit::INCH
;
507 XMLMutableAttributeList
*XMLTransformerBase::ProcessAttrList(
508 Reference
< XAttributeList
>& rAttrList
, sal_uInt16 nActionMap
,
511 XMLMutableAttributeList
*pMutableAttrList
= 0;
512 XMLTransformerActions
*pActions
= GetUserDefinedActions( nActionMap
);
513 OSL_ENSURE( pActions
, "go no actions" );
516 sal_Int16 nAttrCount
= rAttrList
.is() ? rAttrList
->getLength() : 0;
517 for( sal_Int16 i
=0; i
< nAttrCount
; ++i
)
519 const OUString
& rAttrName
= rAttrList
->getNameByIndex( i
);
520 const OUString
& rAttrValue
= rAttrList
->getValueByIndex( i
);
522 sal_uInt16 nPrefix
= GetNamespaceMap().GetKeyByAttrName( rAttrName
,
525 XMLTransformerActions::key_type
aKey( nPrefix
, aLocalName
);
526 XMLTransformerActions::const_iterator aIter
=
527 pActions
->find( aKey
);
528 if( !(aIter
== pActions
->end() ) )
530 if( !pMutableAttrList
)
532 pMutableAttrList
= new XMLMutableAttributeList( rAttrList
,
534 rAttrList
= pMutableAttrList
;
537 sal_uInt32 nAction
= (*aIter
).second
.m_nActionType
;
538 bool bRename
= false;
541 case XML_ATACTION_RENAME
:
544 case XML_ATACTION_COPY
:
546 case XML_ATACTION_REMOVE
:
547 case XML_ATACTION_STYLE_DISPLAY_NAME
:
548 pMutableAttrList
->RemoveAttributeByIndex( i
);
552 case XML_ATACTION_RENAME_IN2INCH
:
554 case XML_ATACTION_IN2INCH
:
556 OUString
aAttrValue( rAttrValue
);
557 if( ReplaceSingleInWithInch( aAttrValue
) )
558 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
561 case XML_ATACTION_INS2INCHS
:
563 OUString
aAttrValue( rAttrValue
);
564 if( ReplaceInWithInch( aAttrValue
) )
565 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
568 case XML_ATACTION_RENAME_INCH2IN
:
570 case XML_ATACTION_INCH2IN
:
572 OUString
aAttrValue( rAttrValue
);
573 if( ReplaceSingleInchWithIn( aAttrValue
) )
574 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
577 case XML_ATACTION_INCHS2INS
:
579 OUString
aAttrValue( rAttrValue
);
580 if( ReplaceInchWithIn( aAttrValue
) )
581 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
584 case XML_ATACTION_TWIPS2IN
:
586 OUString
aAttrValue( rAttrValue
);
588 XMLTransformerBase::ReplaceSingleInchWithIn( aAttrValue
);
591 sal_Int16
const nDestUnit
= lcl_getUnit(aAttrValue
);
593 // convert twips value to inch
595 if (::sax::Converter::convertMeasure(nMeasure
,
596 aAttrValue
, util::MeasureUnit::MM_100TH
))
599 // #i13778#,#i36248# apply correct twip-to-1/100mm
600 nMeasure
= (sal_Int32
)( nMeasure
>= 0
601 ? ((nMeasure
*127+36)/72)
602 : ((nMeasure
*127-36)/72) );
604 OUStringBuffer aBuffer
;
605 ::sax::Converter::convertMeasure(aBuffer
,
606 nMeasure
, util::MeasureUnit::MM_100TH
,
608 aAttrValue
= aBuffer
.makeStringAndClear();
612 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
615 case XML_ATACTION_RENAME_DECODE_STYLE_NAME_REF
:
617 case XML_ATACTION_DECODE_STYLE_NAME
:
618 case XML_ATACTION_DECODE_STYLE_NAME_REF
:
620 OUString
aAttrValue( rAttrValue
);
621 if( DecodeStyleName(aAttrValue
) )
622 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
625 case XML_ATACTION_ENCODE_STYLE_NAME
:
627 OUString
aAttrValue( rAttrValue
);
628 if( EncodeStyleName(aAttrValue
) )
630 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
631 OUString
aNewAttrQName(
632 GetNamespaceMap().GetQNameByKey(
634 ::xmloff::token::GetXMLToken(
635 XML_DISPLAY_NAME
) ) );
636 pMutableAttrList
->AddAttribute( aNewAttrQName
,
641 case XML_ATACTION_RENAME_ENCODE_STYLE_NAME_REF
:
643 case XML_ATACTION_ENCODE_STYLE_NAME_REF
:
645 OUString
aAttrValue( rAttrValue
);
646 if( EncodeStyleName(aAttrValue
) )
647 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
650 case XML_ATACTION_RENAME_NEG_PERCENT
:
652 case XML_ATACTION_NEG_PERCENT
:
654 OUString
aAttrValue( rAttrValue
);
655 if( NegPercent( aAttrValue
) )
656 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
659 case XML_ATACTION_RENAME_ADD_NAMESPACE_PREFIX
:
661 case XML_ATACTION_ADD_NAMESPACE_PREFIX
:
663 OUString
aAttrValue( rAttrValue
);
664 sal_uInt16 nValPrefix
=
665 static_cast<sal_uInt16
>(
666 bRename
? (*aIter
).second
.m_nParam2
667 : (*aIter
).second
.m_nParam1
);
668 if( AddNamespacePrefix( aAttrValue
, nValPrefix
) )
669 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
672 case XML_ATACTION_ADD_APP_NAMESPACE_PREFIX
:
674 OUString
aAttrValue( rAttrValue
);
675 sal_uInt16 nValPrefix
=
676 static_cast<sal_uInt16
>((*aIter
).second
.m_nParam1
);
677 if( IsXMLToken( GetClass(), XML_SPREADSHEET
) )
678 nValPrefix
= XML_NAMESPACE_OOOC
;
679 else if( IsXMLToken( GetClass(), XML_TEXT
) )
680 nValPrefix
= XML_NAMESPACE_OOOW
;
681 if( AddNamespacePrefix( aAttrValue
, nValPrefix
) )
682 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
685 case XML_ATACTION_RENAME_REMOVE_NAMESPACE_PREFIX
:
687 case XML_ATACTION_REMOVE_NAMESPACE_PREFIX
:
689 OUString
aAttrValue( rAttrValue
);
690 sal_uInt16 nValPrefix
=
691 static_cast<sal_uInt16
>(
692 bRename
? (*aIter
).second
.m_nParam2
693 : (*aIter
).second
.m_nParam1
);
694 if( RemoveNamespacePrefix( aAttrValue
, nValPrefix
) )
695 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
698 case XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX
:
700 OUString
aAttrValue( rAttrValue
);
701 if( RemoveNamespacePrefix( aAttrValue
) )
702 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
705 case XML_ATACTION_URI_OOO
:
707 OUString
aAttrValue( rAttrValue
);
708 if( ConvertURIToOASIS( aAttrValue
,
709 static_cast< bool >((*aIter
).second
.m_nParam1
)))
710 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
713 case XML_ATACTION_URI_OASIS
:
715 OUString
aAttrValue( rAttrValue
);
716 if( ConvertURIToOOo( aAttrValue
,
717 static_cast< bool >((*aIter
).second
.m_nParam1
)))
718 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
721 case XML_ATACTION_RENAME_ATTRIBUTE
:
723 OUString
aAttrValue( rAttrValue
);
724 RenameAttributeValue(
726 (*aIter
).second
.m_nParam1
,
727 (*aIter
).second
.m_nParam2
,
728 (*aIter
).second
.m_nParam3
);
729 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
732 case XML_ATACTION_RNG2ISO_DATETIME
:
734 OUString
aAttrValue( rAttrValue
);
735 if( ConvertRNGDateTimeToISO( aAttrValue
))
736 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
739 case XML_ATACTION_RENAME_RNG2ISO_DATETIME
:
741 OUString
aAttrValue( rAttrValue
);
742 if( ConvertRNGDateTimeToISO( aAttrValue
))
743 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
747 case XML_ATACTION_IN2TWIPS
:
749 OUString
aAttrValue( rAttrValue
);
750 XMLTransformerBase::ReplaceSingleInWithInch( aAttrValue
);
754 sal_Int16
const nDestUnit
= lcl_getUnit(aAttrValue
);
756 // convert inch value to twips and export as faked inch
758 if (::sax::Converter::convertMeasure(nMeasure
,
759 aAttrValue
, util::MeasureUnit::MM_100TH
))
762 // #i13778#,#i36248#/ apply correct 1/100mm-to-twip conversion
763 nMeasure
= (sal_Int32
)( nMeasure
>= 0
764 ? ((nMeasure
*72+63)/127)
765 : ((nMeasure
*72-63)/127) );
767 OUStringBuffer aBuffer
;
768 ::sax::Converter::convertMeasure( aBuffer
,
769 nMeasure
, util::MeasureUnit::MM_100TH
,
771 aAttrValue
= aBuffer
.makeStringAndClear();
775 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
778 case XML_ATACTION_SVG_WIDTH_HEIGHT_OOO
:
780 OUString
aAttrValue( rAttrValue
);
781 ReplaceSingleInchWithIn( aAttrValue
);
783 sal_Int16
const nDestUnit
= lcl_getUnit( aAttrValue
);
786 if (::sax::Converter::convertMeasure(nMeasure
,
787 aAttrValue
, util::MeasureUnit::MM_100TH
))
792 else if( nMeasure
< 0 )
796 OUStringBuffer aBuffer
;
797 ::sax::Converter::convertMeasure(aBuffer
, nMeasure
,
798 util::MeasureUnit::MM_100TH
, nDestUnit
);
799 aAttrValue
= aBuffer
.makeStringAndClear();
802 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
805 case XML_ATACTION_SVG_WIDTH_HEIGHT_OASIS
:
807 OUString
aAttrValue( rAttrValue
);
808 ReplaceSingleInWithInch( aAttrValue
);
810 sal_Int16
const nDestUnit
= lcl_getUnit( aAttrValue
);
813 if (::sax::Converter::convertMeasure(nMeasure
,
814 aAttrValue
, util::MeasureUnit::MM_100TH
))
819 else if( nMeasure
< 0 )
823 OUStringBuffer aBuffer
;
824 ::sax::Converter::convertMeasure(aBuffer
, nMeasure
,
825 util::MeasureUnit::MM_100TH
, nDestUnit
);
826 aAttrValue
= aBuffer
.makeStringAndClear();
829 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
832 case XML_ATACTION_DECODE_ID
:
834 const sal_Int32 nLen
= rAttrValue
.getLength();
835 OUStringBuffer aBuffer
;
838 for( pos
= 0; pos
< nLen
; pos
++ )
840 sal_Unicode c
= rAttrValue
[pos
];
841 if( (c
>= '0') && (c
<= '9') )
844 aBuffer
.append( (sal_Int32
)c
);
847 pMutableAttrList
->SetValueByIndex( i
, aBuffer
.makeStringAndClear() );
850 // #i50322# - special handling for the
851 // transparency of writer background graphics.
852 case XML_ATACTION_WRITER_BACK_GRAPHIC_TRANSPARENCY
:
854 // determine, if it's the transparency of a document style
855 XMLTransformerContext
* pFirstContext
= (*m_pContexts
)[0].get();
856 OUString aFirstContextLocalName
;
857 /* sal_uInt16 nFirstContextPrefix = */
858 GetNamespaceMap().GetKeyByAttrName( pFirstContext
->GetQName(),
859 &aFirstContextLocalName
);
860 bool bIsDocumentStyle(
861 ::xmloff::token::IsXMLToken( aFirstContextLocalName
,
862 XML_DOCUMENT_STYLES
) );
863 // no conversion of transparency value for document
864 // styles, because former OpenOffice.org version writes
865 // writes always a transparency value of 100% and doesn't
866 // read the value. Thus, it's intepreted as 0%
867 if ( !bIsDocumentStyle
)
869 OUString
aAttrValue( rAttrValue
);
870 NegPercent(aAttrValue
);
871 pMutableAttrList
->SetValueByIndex( i
, aAttrValue
);
876 case XML_ATACTION_SHAPEID
:
878 OUString
sNewValue( "shape" );
879 sNewValue
+= rAttrValue
;
880 pMutableAttrList
->SetValueByIndex( i
, sNewValue
);
885 OSL_ENSURE( false, "unknown action" );
891 OUString
aNewAttrQName(
892 GetNamespaceMap().GetQNameByKey(
893 (*aIter
).second
.GetQNamePrefixFromParam1(),
894 ::xmloff::token::GetXMLToken(
895 (*aIter
).second
.GetQNameTokenFromParam1()) ) );
896 pMutableAttrList
->RenameAttributeByIndex( i
,
903 return pMutableAttrList
;
906 bool XMLTransformerBase::ReplaceSingleInchWithIn( OUString
& rValue
)
909 sal_Int32 nPos
= rValue
.getLength();
910 while( nPos
&& rValue
[nPos
-1] <= ' ' )
913 ('c'==rValue
[nPos
-2] || 'C'==rValue
[nPos
-2]) &&
914 ('h'==rValue
[nPos
-1] || 'H'==rValue
[nPos
-1]) )
916 rValue
=rValue
.copy( 0, nPos
-2 );
923 bool XMLTransformerBase::ReplaceInchWithIn( OUString
& rValue
)
927 while( nPos
< rValue
.getLength()-3 )
929 sal_Unicode c
= rValue
[nPos
];
930 if( 'i'==c
|| 'I'==c
)
933 if( (c
>= '0' && c
<= '9') || '.' == c
)
936 if( 'n'==c
|| 'N'==c
)
939 if( 'c'==c
|| 'C'==c
)
942 if( 'h'==c
|| 'H'==c
)
944 rValue
= rValue
.replaceAt( nPos
,
945 4, GetXMLToken(XML_UNIT_INCH
) );
960 bool XMLTransformerBase::ReplaceSingleInWithInch( OUString
& rValue
)
964 sal_Int32 nPos
= rValue
.getLength();
965 while( nPos
&& rValue
[nPos
-1] <= ' ' )
968 ('i'==rValue
[nPos
-2] ||
969 'I'==rValue
[nPos
-2]) &&
970 ('n'==rValue
[nPos
-1] ||
971 'N'==rValue
[nPos
-1]) )
974 rValue
= rValue
.replaceAt( nPos
, rValue
.getLength() - nPos
,
975 GetXMLToken(XML_INCH
) );
982 bool XMLTransformerBase::ReplaceInWithInch( OUString
& rValue
)
986 while( nPos
< rValue
.getLength()-1 )
988 sal_Unicode c
= rValue
[nPos
];
989 if( 'i'==c
|| 'I'==c
)
992 if( (c
>= '0' && c
<= '9') || '.' == c
)
995 if( 'n'==c
|| 'N'==c
)
997 rValue
= rValue
.replaceAt( nPos
,
998 2, GetXMLToken(XML_INCH
) );
1011 bool XMLTransformerBase::EncodeStyleName( OUString
& rName
) const
1013 static const sal_Char aHexTab
[] = "0123456789abcdef";
1015 bool bEncoded
= false;
1017 sal_Int32 nLen
= rName
.getLength();
1018 OUStringBuffer
aBuffer( nLen
);
1020 for( sal_Int32 i
= 0; i
< nLen
; i
++ )
1022 sal_Unicode c
= rName
[i
];
1023 bool bValidChar
= false;
1027 (c
>= 0x0041 && c
<= 0x005a) ||
1028 (c
>= 0x0061 && c
<= 0x007a) ||
1029 (c
>= 0x00c0 && c
<= 0x00d6) ||
1030 (c
>= 0x00d8 && c
<= 0x00f6) ||
1031 (c
>= 0x00f8 && c
<= 0x00ff) ||
1032 ( i
> 0 && ( (c
>= 0x0030 && c
<= 0x0039) ||
1033 c
== 0x00b7 || c
== '-' || c
== '.') );
1037 if( (c
>= 0xf900U
&& c
<= 0xfffeU
) ||
1038 (c
>= 0x20ddU
&& c
<= 0x20e0U
))
1042 else if( (c
>= 0x02bbU
&& c
<= 0x02c1U
) || c
== 0x0559 ||
1043 c
== 0x06e5 || c
== 0x06e6 )
1047 else if( c
== 0x0387 )
1053 if( !xCharClass
.is() )
1055 const_cast < XMLTransformerBase
* >(this)
1056 ->xCharClass
= CharacterClassification::create( comphelper::getProcessComponentContext() );
1058 sal_Int16 nType
= xCharClass
->getType( rName
, i
);
1062 case UnicodeType::UPPERCASE_LETTER
: // Lu
1063 case UnicodeType::LOWERCASE_LETTER
: // Ll
1064 case UnicodeType::TITLECASE_LETTER
: // Lt
1065 case UnicodeType::OTHER_LETTER
: // Lo
1066 case UnicodeType::LETTER_NUMBER
: // Nl
1069 case UnicodeType::NON_SPACING_MARK
: // Ms
1070 case UnicodeType::ENCLOSING_MARK
: // Me
1071 case UnicodeType::COMBINING_SPACING_MARK
: //Mc
1072 case UnicodeType::MODIFIER_LETTER
: // Lm
1073 case UnicodeType::DECIMAL_DIGIT_NUMBER
: // Nd
1081 aBuffer
.append( c
);
1085 aBuffer
.append( '_' );
1087 aBuffer
.append( static_cast< sal_Unicode
>(
1088 aHexTab
[ (c
>> 12) & 0x0f ] ) );
1090 aBuffer
.append( static_cast< sal_Unicode
>(
1091 aHexTab
[ (c
>> 8) & 0x0f ] ) );
1093 aBuffer
.append( static_cast< sal_Unicode
>(
1094 aHexTab
[ (c
>> 4) & 0x0f ] ) );
1095 aBuffer
.append( static_cast< sal_Unicode
>(
1096 aHexTab
[ c
& 0x0f ] ) );
1097 aBuffer
.append( '_' );
1102 if( aBuffer
.getLength() > (1<<15)-1 )
1106 rName
= aBuffer
.makeStringAndClear();
1110 bool XMLTransformerBase::DecodeStyleName( OUString
& rName
)
1112 bool bEncoded
= false;
1114 sal_Int32 nLen
= rName
.getLength();
1115 OUStringBuffer
aBuffer( nLen
);
1117 bool bWithinHex
= false;
1118 sal_Unicode cEnc
= 0;
1119 for( sal_Int32 i
= 0; i
< nLen
; i
++ )
1121 sal_Unicode c
= rName
[i
];
1126 aBuffer
.append( cEnc
);
1133 bWithinHex
= !bWithinHex
;
1135 else if( bWithinHex
)
1138 if( c
>= '0' && c
<= '9' )
1142 else if( c
>= 'a' && c
<= 'f' )
1144 cDigit
= c
- 'a' + 10;
1146 else if( c
>= 'A' && c
<= 'F' )
1148 cDigit
= c
- 'A' + 10;
1156 cEnc
= (cEnc
<< 4) + cDigit
;
1160 aBuffer
.append( c
);
1165 rName
= aBuffer
.makeStringAndClear();
1169 bool XMLTransformerBase::NegPercent( OUString
& rValue
)
1176 sal_Int32 nLen
= rValue
.getLength();
1179 while( nPos
< nLen
&& ' ' == rValue
[nPos
] )
1182 if( nPos
< nLen
&& '-' == rValue
[nPos
] )
1189 while( nPos
< nLen
&&
1190 '0' <= rValue
[nPos
] &&
1191 '9' >= rValue
[nPos
] )
1193 // TODO: check overflow!
1195 nVal
+= (rValue
[nPos
] - '0');
1198 if( nPos
< nLen
&& '.' == rValue
[nPos
] )
1203 while( nPos
< nLen
&&
1204 '0' <= rValue
[nPos
] &&
1205 '9' >= rValue
[nPos
] )
1207 // TODO: check overflow!
1209 nVal
+= ( static_cast<double>(rValue
[nPos
] - '0') / nDiv
);
1215 while( nPos
< nLen
&& ' ' == rValue
[nPos
] )
1218 if( nPos
< nLen
&& '%' == rValue
[nPos
] )
1224 sal_Int32 nIntVal
= 100 - static_cast<sal_Int32
>( nVal
);
1226 rValue
= OUString::number(nIntVal
) + "%";
1234 bool XMLTransformerBase::AddNamespacePrefix( OUString
& rName
,
1235 sal_uInt16 nPrefix
) const
1237 rName
= GetNamespaceMap().GetQNameByKey( nPrefix
, rName
, false );
1241 bool XMLTransformerBase::RemoveNamespacePrefix( OUString
& rName
,
1242 sal_uInt16 nPrefixOnly
) const
1244 OUString aLocalName
;
1245 sal_uInt16 nPrefix
=
1246 GetNamespaceMap()._GetKeyByAttrName( rName
, &aLocalName
, false );
1247 bool bRet
= XML_NAMESPACE_UNKNOWN
!= nPrefix
&&
1248 (USHRT_MAX
== nPrefixOnly
|| nPrefix
== nPrefixOnly
);
1255 bool XMLTransformerBase::ConvertURIToOASIS( OUString
& rURI
,
1256 bool bSupportPackage
) const
1259 if( !m_aExtPathPrefix
.isEmpty() && !rURI
.isEmpty() )
1266 // for package URIs, the '#' has to be removed
1267 if( bSupportPackage
)
1269 rURI
= rURI
.copy( 1 );
1274 // no rel path; nothing to do
1277 // a rel path; to keep URI simple, remove './', if there
1279 if( rURI
.getLength() > 1 && '/' == rURI
[1] )
1281 rURI
= rURI
.copy( 2 );
1286 // check for a RFC2396 schema
1290 sal_Int32 nLen
= rURI
.getLength();
1291 while( nPos
< nLen
)
1293 switch( rURI
[nPos
] )
1296 // a relative path segement
1297 nPos
= nLen
; // leave loop
1302 nPos
= nLen
; // leave loop
1305 // we don't care about any other characters
1315 OUString
sTmp( m_aExtPathPrefix
);
1325 bool XMLTransformerBase::ConvertURIToOOo( OUString
& rURI
,
1326 bool bSupportPackage
) const
1329 if( !rURI
.isEmpty() )
1331 bool bPackage
= false;
1335 // no rel path; nothing to do
1339 if( rURI
.startsWith( m_aExtPathPrefix
) )
1341 // an external URI; remove '../'
1342 rURI
= rURI
.copy( m_aExtPathPrefix
.getLength() );
1351 // check for a RFC2396 schema
1355 sal_Int32 nLen
= rURI
.getLength();
1356 while( nPos
< nLen
)
1358 switch( rURI
[nPos
] )
1361 // a relative path segement within the package
1362 nPos
= nLen
; // leave loop
1367 nPos
= nLen
; // leave loop
1370 // we don't care about any other characters
1378 if( bPackage
&& bSupportPackage
)
1380 OUString
sTmp( '#' );
1381 if( rURI
.startsWith( "./" ) )
1382 rURI
= rURI
.copy( 2 );
1392 bool XMLTransformerBase::RenameAttributeValue(
1393 OUString
& rOutAttributeValue
,
1398 return ( lcl_ConvertAttr( rOutAttributeValue
, nParam1
) ||
1399 lcl_ConvertAttr( rOutAttributeValue
, nParam2
) ||
1400 lcl_ConvertAttr( rOutAttributeValue
, nParam3
) );
1404 bool XMLTransformerBase::ConvertRNGDateTimeToISO( OUString
& rDateTime
)
1406 if( !rDateTime
.isEmpty() &&
1407 rDateTime
.indexOf( '.' ) != -1 )
1409 rDateTime
= rDateTime
.replace( '.', ',');
1416 XMLTokenEnum
XMLTransformerBase::GetToken( const OUString
& rStr
) const
1418 XMLTransformerTokenMap::const_iterator aIter
=
1419 m_pTokenMap
->find( rStr
);
1420 if( aIter
== m_pTokenMap
->end() )
1421 return XML_TOKEN_END
;
1423 return (*aIter
).second
;
1428 const XMLTransformerContext
*XMLTransformerBase::GetCurrentContext() const
1430 OSL_ENSURE( !m_pContexts
->empty(), "empty stack" );
1433 return m_pContexts
->empty() ? 0 : m_pContexts
->back().get();
1436 const XMLTransformerContext
*XMLTransformerBase::GetAncestorContext(
1437 sal_uInt32 n
) const
1439 XMLTransformerContextVector::size_type nSize
=
1440 m_pContexts
->size();
1441 XMLTransformerContextVector::size_type nPos
=
1442 static_cast<XMLTransformerContextVector::size_type
>( n
);
1444 OSL_ENSURE( nSize
>nPos
+2 , "invalid context" );
1446 return nSize
> nPos
+2 ? (*m_pContexts
)[nSize
-(nPos
+2)].get() : 0;
1449 bool XMLTransformerBase::isWriter() const
1451 Reference
< XServiceInfo
> xSI( mxModel
, UNO_QUERY
);
1453 ( xSI
->supportsService("com.sun.star.text.TextDocument") ||
1454 xSI
->supportsService("com.sun.star.text.WebDocument") ||
1455 xSI
->supportsService("com.sun.star.text.GlobalDocument") );
1458 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */