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 <tools/UnitConversion.hxx>
23 #include <osl/diagnose.h>
24 #include <com/sun/star/i18n/CharacterClassification.hpp>
25 #include <com/sun/star/i18n/UnicodeType.hpp>
26 #include <com/sun/star/util/MeasureUnit.hpp>
27 #include <sax/tools/converter.hxx>
28 #include <comphelper/processfactory.hxx>
29 #include <xmloff/namespacemap.hxx>
30 #include <xmloff/xmlnamespace.hxx>
31 #include "IgnoreTContext.hxx"
32 #include "RenameElemTContext.hxx"
33 #include "ProcAttrTContext.hxx"
34 #include "ProcAddAttrTContext.hxx"
35 #include "MergeElemTContext.hxx"
36 #include "CreateElemTContext.hxx"
37 #include "MutableAttrList.hxx"
38 #include "TransformerActions.hxx"
39 #include "ElemTransformerAction.hxx"
40 #include "PropertyActionsOOo.hxx"
41 #include "TransformerTokenMap.hxx"
43 #include "TransformerBase.hxx"
44 #include <xmloff/xmlimp.hxx>
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_PROC_ATTRS_COND
:
128 const XMLTransformerContext
*pCurrent
= GetCurrentContext();
129 if( pCurrent
->HasQName(
130 (*aIter
).second
.GetQNamePrefixFromParam3(),
131 (*aIter
).second
.GetQNameTokenFromParam3() ) )
132 return new XMLProcAttrTransformerContext( *this, rQName
,
133 (*aIter
).second
.GetQNamePrefixFromParam1(),
134 (*aIter
).second
.GetQNameTokenFromParam1(),
135 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam2
) );
137 return new XMLProcAttrTransformerContext( *this, rQName
,
138 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam2
) );
140 case XML_ETACTION_PROC_ATTRS
:
141 return new XMLProcAttrTransformerContext( *this, rQName
,
142 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam1
) );
143 case XML_ETACTION_PROC_ATTRS_COND
:
145 const XMLTransformerContext
*pCurrent
= GetCurrentContext();
146 if( pCurrent
->HasQName(
147 (*aIter
).second
.GetQNamePrefixFromParam1(),
148 (*aIter
).second
.GetQNameTokenFromParam1() ) )
149 return new XMLProcAttrTransformerContext( *this, rQName
,
150 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam2
) );
153 case XML_ETACTION_MOVE_ATTRS_TO_ELEMS
:
154 return new XMLCreateElemTransformerContext( *this, rQName
,
155 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam1
) );
156 case XML_ETACTION_MOVE_ELEMS_TO_ATTRS
:
157 return new XMLMergeElemTransformerContext( *this, rQName
,
158 static_cast< sal_uInt16
>( (*aIter
).second
.m_nParam1
) );
160 OSL_ENSURE( false, "unknown action" );
165 // default is copying
166 return new XMLTransformerContext( *this, rQName
);
169 XMLTransformerActions
*XMLTransformerBase::GetUserDefinedActions( sal_uInt16
)
174 XMLTransformerBase::XMLTransformerBase( XMLTransformerActionInit
const *pInit
,
175 ::xmloff::token::XMLTokenEnum
const *pTKMapInit
)
177 m_pNamespaceMap( new SvXMLNamespaceMap
),
178 m_ElemActions( pInit
),
179 m_TokenMap( pTKMapInit
)
181 GetNamespaceMap().Add( GetXMLToken(XML_NP_XLINK
), GetXMLToken(XML_N_XLINK
), XML_NAMESPACE_XLINK
);
182 GetNamespaceMap().Add( GetXMLToken(XML_NP_DC
), GetXMLToken(XML_N_DC
), XML_NAMESPACE_DC
);
183 GetNamespaceMap().Add( GetXMLToken(XML_NP_MATH
), GetXMLToken(XML_N_MATH
), XML_NAMESPACE_MATH
);
184 GetNamespaceMap().Add( GetXMLToken(XML_NP_OOO
), GetXMLToken(XML_N_OOO
), XML_NAMESPACE_OOO
);
185 GetNamespaceMap().Add( GetXMLToken(XML_NP_DOM
), GetXMLToken(XML_N_DOM
), XML_NAMESPACE_DOM
);
186 GetNamespaceMap().Add( GetXMLToken(XML_NP_OOOW
), GetXMLToken(XML_N_OOOW
), XML_NAMESPACE_OOOW
);
187 GetNamespaceMap().Add( GetXMLToken(XML_NP_OOOC
), GetXMLToken(XML_N_OOOC
), XML_NAMESPACE_OOOC
);
190 XMLTransformerBase::~XMLTransformerBase() noexcept
194 void SAL_CALL
XMLTransformerBase::startDocument()
196 m_xHandler
->startDocument();
199 void SAL_CALL
XMLTransformerBase::endDocument()
201 m_xHandler
->endDocument();
204 void SAL_CALL
XMLTransformerBase::startElement( const OUString
& rName
,
205 const Reference
< XAttributeList
>& rAttrList
)
207 std::unique_ptr
<SvXMLNamespaceMap
> pRewindMap
;
209 // Process namespace attributes. This must happen before creating the
210 // context, because namespace declaration apply to the element name itself.
211 rtl::Reference
<XMLMutableAttributeList
> pMutableAttrList
;
212 Reference
< XAttributeList
> xAttrList( rAttrList
);
213 sal_Int16 nAttrCount
= xAttrList
.is() ? xAttrList
->getLength() : 0;
214 for( sal_Int16 i
=0; i
< nAttrCount
; i
++ )
216 const OUString aAttrName
= xAttrList
->getNameByIndex( i
);
217 if( ( aAttrName
.getLength() >= 5 ) &&
218 ( aAttrName
.startsWith( GetXMLToken(XML_XMLNS
) ) ) &&
219 ( aAttrName
.getLength() == 5 || ':' == aAttrName
[5] ) )
223 pRewindMap
= std::move(m_pNamespaceMap
);
224 m_pNamespaceMap
.reset( new SvXMLNamespaceMap( *pRewindMap
) );
226 const OUString aAttrValue
= xAttrList
->getValueByIndex( i
);
228 OUString
aPrefix( ( aAttrName
.getLength() == 5 )
230 : aAttrName
.copy( 6 ) );
231 // Add namespace, but only if it is known.
232 sal_uInt16 nKey
= m_pNamespaceMap
->AddIfKnown( aPrefix
, aAttrValue
);
233 // If namespace is unknown, try to match a name with similar
235 if( XML_NAMESPACE_UNKNOWN
== nKey
)
237 OUString
aTestName( aAttrValue
);
238 if( SvXMLNamespaceMap::NormalizeOasisURN( aTestName
) )
239 nKey
= m_pNamespaceMap
->AddIfKnown( aPrefix
, aTestName
);
241 // If that namespace is not known, too, add it as unknown
242 if( XML_NAMESPACE_UNKNOWN
== nKey
)
243 nKey
= m_pNamespaceMap
->Add( aPrefix
, aAttrValue
);
245 const OUString
& rRepName
= m_vReplaceNamespaceMap
.GetNameByKey( nKey
);
246 if( !rRepName
.isEmpty() )
248 if( !pMutableAttrList
)
250 pMutableAttrList
= new XMLMutableAttributeList( xAttrList
);
251 xAttrList
= pMutableAttrList
;
254 pMutableAttrList
->SetValueByIndex( i
, rRepName
);
259 // Get element's namespace and local name.
262 m_pNamespaceMap
->GetKeyByAttrName( rName
, &aLocalName
);
264 // If there are contexts already, call a CreateChildContext at the topmost
265 // context. Otherwise, create a default context.
266 ::rtl::Reference
< XMLTransformerContext
> xContext
;
267 if( !m_vContexts
.empty() )
269 xContext
= m_vContexts
.back()->CreateChildContext( nPrefix
,
276 xContext
= CreateContext( nPrefix
, aLocalName
, rName
);
279 OSL_ENSURE( xContext
.is(), "XMLTransformerBase::startElement: missing context" );
281 xContext
= new XMLTransformerContext( *this, rName
);
283 // Remember old namespace map.
285 xContext
->PutRewindMap( std::move(pRewindMap
) );
287 // Push context on stack.
288 m_vContexts
.push_back( xContext
);
290 // Call a startElement at the new context.
291 xContext
->StartElement( xAttrList
);
294 void SAL_CALL
XMLTransformerBase::endElement( const OUString
&
295 #if OSL_DEBUG_LEVEL > 0
300 if( m_vContexts
.empty() )
303 // Get topmost context
304 ::rtl::Reference
< XMLTransformerContext
> xContext
= m_vContexts
.back();
306 #if OSL_DEBUG_LEVEL > 0
307 OSL_ENSURE( xContext
->GetQName() == rName
,
308 "XMLTransformerBase::endElement: popped context has wrong lname" );
311 // Call a EndElement at the current context.
312 xContext
->EndElement();
314 // and remove it from the stack.
315 m_vContexts
.pop_back();
317 // Get a namespace map to rewind.
318 std::unique_ptr
<SvXMLNamespaceMap
> pRewindMap
= xContext
->TakeRewindMap();
320 // Delete the current context.
323 // Rewind a namespace map.
326 m_pNamespaceMap
= std::move( pRewindMap
);
330 void SAL_CALL
XMLTransformerBase::characters( const OUString
& rChars
)
332 if( !m_vContexts
.empty() )
334 m_vContexts
.back()->Characters( rChars
);
338 void SAL_CALL
XMLTransformerBase::ignorableWhitespace( const OUString
& rWhitespaces
)
340 m_xHandler
->ignorableWhitespace( rWhitespaces
);
343 void SAL_CALL
XMLTransformerBase::processingInstruction( const OUString
& rTarget
,
344 const OUString
& rData
)
346 m_xHandler
->processingInstruction( rTarget
, rData
);
349 void SAL_CALL
XMLTransformerBase::setDocumentLocator( const Reference
< XLocator
>& )
353 // XExtendedDocumentHandler
354 void SAL_CALL
XMLTransformerBase::startCDATA()
358 void SAL_CALL
XMLTransformerBase::endCDATA()
362 void SAL_CALL
XMLTransformerBase::comment( const OUString
& /*rComment*/ )
366 void SAL_CALL
XMLTransformerBase::allowLineBreak()
370 void SAL_CALL
XMLTransformerBase::unknown( const OUString
& /*rString*/ )
375 void SAL_CALL
XMLTransformerBase::initialize( const Sequence
< Any
>& aArguments
)
377 for( const auto& rArgument
: aArguments
)
379 // use isAssignableFrom instead of comparing the types to
380 // allow XExtendedDocumentHandler instead of XDocumentHandler (used in
381 // writeOasis2OOoLibraryElement in sfx2).
382 // The Any shift operator can't be used to query the type because it
383 // uses queryInterface, and the model also has a XPropertySet interface.
385 css::uno::Reference
< XFastDocumentHandler
> xFastHandler
;
386 if( (rArgument
>>= xFastHandler
) && xFastHandler
)
388 SvXMLImport
*pFastHandler
= static_cast<SvXMLImport
*>( xFastHandler
.get() );
389 m_xHandler
.set( new SvXMLLegacyToFastDocHandler( pFastHandler
) );
392 else if( cppu::UnoType
<XDocumentHandler
>::get().isAssignableFrom( rArgument
.getValueType() ) )
394 m_xHandler
.set( rArgument
, UNO_QUERY
);
396 // property set to transport data across
397 else if( cppu::UnoType
<XPropertySet
>::get().isAssignableFrom( rArgument
.getValueType() ) )
398 m_xPropSet
.set( rArgument
, UNO_QUERY
);
400 else if( cppu::UnoType
<css::frame::XModel
>::get().isAssignableFrom( rArgument
.getValueType() ) )
401 mxModel
.set( rArgument
, UNO_QUERY
);
404 if( m_xPropSet
.is() )
407 OUString sRelPath
, sName
;
408 Reference
< XPropertySetInfo
> xPropSetInfo
=
409 m_xPropSet
->getPropertySetInfo();
410 OUString
sPropName( u
"StreamRelPath"_ustr
);
411 if( xPropSetInfo
->hasPropertyByName(sPropName
) )
413 aAny
= m_xPropSet
->getPropertyValue(sPropName
);
416 sPropName
= "StreamName";
417 if( xPropSetInfo
->hasPropertyByName(sPropName
) )
419 aAny
= m_xPropSet
->getPropertyValue(sPropName
);
422 if( !sName
.isEmpty() )
424 m_aExtPathPrefix
= "../";
426 // If there is a rel path within a package, then append
427 // additional '../'. If the rel path contains an ':', then it is
428 // an absolute URI (or invalid URI, because zip files don't
429 // permit ':'), and it will be ignored.
430 if( !sRelPath
.isEmpty() )
432 sal_Int32 nColPos
= sRelPath
.indexOf( ':' );
433 OSL_ENSURE( -1 == nColPos
,
434 "StreamRelPath contains ':', absolute URI?" );
438 OUString sTmp
= m_aExtPathPrefix
;
442 m_aExtPathPrefix
+= sTmp
;
443 nPos
= sRelPath
.indexOf( '/', nPos
+ 1 );
452 assert(m_xHandler
.is()); // can't do anything without that
455 static sal_Int16
lcl_getUnit( std::u16string_view rValue
)
457 if( o3tl::endsWithIgnoreAsciiCase( rValue
, "cm" ) )
458 return util::MeasureUnit::CM
;
459 else if ( o3tl::endsWithIgnoreAsciiCase( rValue
, "mm" ) )
460 return util::MeasureUnit::MM
;
462 return util::MeasureUnit::INCH
;
465 XMLMutableAttributeList
*XMLTransformerBase::ProcessAttrList(
466 Reference
< XAttributeList
>& rAttrList
, sal_uInt16 nActionMap
,
469 rtl::Reference
<XMLMutableAttributeList
> pMutableAttrList
;
470 XMLTransformerActions
*pActions
= GetUserDefinedActions( nActionMap
);
471 OSL_ENSURE( pActions
, "go no actions" );
474 sal_Int16 nAttrCount
= rAttrList
.is() ? rAttrList
->getLength() : 0;
475 for( sal_Int16 i
=0; i
< nAttrCount
; ++i
)
477 const OUString aAttrName
= rAttrList
->getNameByIndex( i
);
478 const OUString aAttrValue
= rAttrList
->getValueByIndex( i
);
480 sal_uInt16 nPrefix
= GetNamespaceMap().GetKeyByAttrName( aAttrName
,
483 XMLTransformerActions::key_type
aKey( nPrefix
, aLocalName
);
484 XMLTransformerActions::const_iterator aIter
=
485 pActions
->find( aKey
);
486 if( aIter
!= pActions
->end() )
488 if( !pMutableAttrList
)
490 pMutableAttrList
= new XMLMutableAttributeList( rAttrList
,
492 rAttrList
= pMutableAttrList
;
495 sal_uInt32 nAction
= (*aIter
).second
.m_nActionType
;
496 bool bRename
= false;
499 case XML_ATACTION_RENAME
:
502 case XML_ATACTION_COPY
:
504 case XML_ATACTION_REMOVE
:
505 case XML_ATACTION_STYLE_DISPLAY_NAME
:
506 pMutableAttrList
->RemoveAttributeByIndex( i
);
510 case XML_ATACTION_RENAME_IN2INCH
:
513 case XML_ATACTION_IN2INCH
:
515 OUString
aAttrValue2( aAttrValue
);
516 if( ReplaceSingleInWithInch( aAttrValue2
) )
517 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
520 case XML_ATACTION_INS2INCHS
:
522 OUString
aAttrValue2( aAttrValue
);
523 if( ReplaceInWithInch( aAttrValue2
) )
524 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
527 case XML_ATACTION_RENAME_INCH2IN
:
530 case XML_ATACTION_INCH2IN
:
532 OUString
aAttrValue2( aAttrValue
);
533 if( ReplaceSingleInchWithIn( aAttrValue2
) )
534 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
537 case XML_ATACTION_INCHS2INS
:
539 OUString
aAttrValue2( aAttrValue
);
540 if( ReplaceInchWithIn( aAttrValue2
) )
541 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
544 case XML_ATACTION_TWIPS2IN
:
546 OUString
aAttrValue2( aAttrValue
);
548 XMLTransformerBase::ReplaceSingleInchWithIn( aAttrValue2
);
551 sal_Int16
const nDestUnit
= lcl_getUnit(aAttrValue2
);
553 // convert twips value to inch
555 if (::sax::Converter::convertMeasure(nMeasure
,
558 nMeasure
= static_cast<sal_Int32
>(convertTwipToMm100(nMeasure
));
560 OUStringBuffer aBuffer
;
561 ::sax::Converter::convertMeasure(aBuffer
,
562 nMeasure
, util::MeasureUnit::MM_100TH
,
564 aAttrValue2
= aBuffer
.makeStringAndClear();
568 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
571 case XML_ATACTION_RENAME_DECODE_STYLE_NAME_REF
:
574 case XML_ATACTION_DECODE_STYLE_NAME
:
575 case XML_ATACTION_DECODE_STYLE_NAME_REF
:
577 OUString
aAttrValue2( aAttrValue
);
578 if( DecodeStyleName(aAttrValue2
) )
579 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
582 case XML_ATACTION_ENCODE_STYLE_NAME
:
584 OUString
aAttrValue2( aAttrValue
);
585 if( EncodeStyleName(aAttrValue2
) )
587 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
588 OUString
aNewAttrQName(
589 GetNamespaceMap().GetQNameByKey(
591 ::xmloff::token::GetXMLToken(
592 XML_DISPLAY_NAME
) ) );
593 pMutableAttrList
->AddAttribute( aNewAttrQName
,
598 case XML_ATACTION_RENAME_ENCODE_STYLE_NAME_REF
:
601 case XML_ATACTION_ENCODE_STYLE_NAME_REF
:
603 OUString
aAttrValue2( aAttrValue
);
604 if( EncodeStyleName(aAttrValue2
) )
605 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
608 case XML_ATACTION_RENAME_NEG_PERCENT
:
611 case XML_ATACTION_NEG_PERCENT
:
613 OUString
aAttrValue2( aAttrValue
);
614 if( NegPercent( aAttrValue2
) )
615 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
618 case XML_ATACTION_RENAME_ADD_NAMESPACE_PREFIX
:
621 case XML_ATACTION_ADD_NAMESPACE_PREFIX
:
623 OUString
aAttrValue2( aAttrValue
);
624 sal_uInt16 nValPrefix
=
625 static_cast<sal_uInt16
>(
626 bRename
? (*aIter
).second
.m_nParam2
627 : (*aIter
).second
.m_nParam1
);
628 AddNamespacePrefix( aAttrValue2
, nValPrefix
);
629 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
632 case XML_ATACTION_ADD_APP_NAMESPACE_PREFIX
:
634 OUString
aAttrValue2( aAttrValue
);
635 sal_uInt16 nValPrefix
=
636 static_cast<sal_uInt16
>((*aIter
).second
.m_nParam1
);
637 if( IsXMLToken( GetClass(), XML_SPREADSHEET
) )
638 nValPrefix
= XML_NAMESPACE_OOOC
;
639 else if( IsXMLToken( GetClass(), XML_TEXT
) )
640 nValPrefix
= XML_NAMESPACE_OOOW
;
641 AddNamespacePrefix( aAttrValue2
, nValPrefix
);
642 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
645 case XML_ATACTION_RENAME_REMOVE_NAMESPACE_PREFIX
:
648 case XML_ATACTION_REMOVE_NAMESPACE_PREFIX
:
650 OUString
aAttrValue2( aAttrValue
);
651 sal_uInt16 nValPrefix
=
652 static_cast<sal_uInt16
>(
653 bRename
? (*aIter
).second
.m_nParam2
654 : (*aIter
).second
.m_nParam1
);
655 if( RemoveNamespacePrefix( aAttrValue2
, nValPrefix
) )
656 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
659 case XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX
:
661 OUString
aAttrValue2( aAttrValue
);
662 if( RemoveNamespacePrefix( aAttrValue2
) )
663 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
666 case XML_ATACTION_URI_OOO
:
668 OUString
aAttrValue2( aAttrValue
);
669 if( ConvertURIToOASIS( aAttrValue2
,
670 static_cast< bool >((*aIter
).second
.m_nParam1
)))
671 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
674 case XML_ATACTION_URI_OASIS
:
676 OUString
aAttrValue2( aAttrValue
);
677 if( ConvertURIToOOo( aAttrValue2
,
678 static_cast< bool >((*aIter
).second
.m_nParam1
)))
679 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
682 case XML_ATACTION_RENAME_ATTRIBUTE
:
684 OUString
aAttrValue2( aAttrValue
);
685 RenameAttributeValue(
687 (*aIter
).second
.m_nParam1
,
688 (*aIter
).second
.m_nParam2
,
689 (*aIter
).second
.m_nParam3
);
690 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
693 case XML_ATACTION_RNG2ISO_DATETIME
:
695 OUString
aAttrValue2( aAttrValue
);
696 if( ConvertRNGDateTimeToISO( aAttrValue2
))
697 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
700 case XML_ATACTION_RENAME_RNG2ISO_DATETIME
:
702 OUString
aAttrValue2( aAttrValue
);
703 if( ConvertRNGDateTimeToISO( aAttrValue2
))
704 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
708 case XML_ATACTION_IN2TWIPS
:
710 OUString
aAttrValue2( aAttrValue
);
711 XMLTransformerBase::ReplaceSingleInWithInch( aAttrValue2
);
715 sal_Int16
const nDestUnit
= lcl_getUnit(aAttrValue2
);
717 // convert inch value to twips and export as faked inch
719 if (::sax::Converter::convertMeasure(nMeasure
,
722 nMeasure
= o3tl::toTwips(nMeasure
, o3tl::Length::mm100
);
724 OUStringBuffer aBuffer
;
725 ::sax::Converter::convertMeasure( aBuffer
,
726 nMeasure
, util::MeasureUnit::MM_100TH
,
728 aAttrValue2
= aBuffer
.makeStringAndClear();
732 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
735 case XML_ATACTION_SVG_WIDTH_HEIGHT_OOO
:
737 OUString
aAttrValue2( aAttrValue
);
738 ReplaceSingleInchWithIn( aAttrValue2
);
740 sal_Int16
const nDestUnit
= lcl_getUnit( aAttrValue2
);
743 if (::sax::Converter::convertMeasure(nMeasure
,
749 else if( nMeasure
< 0 )
753 OUStringBuffer aBuffer
;
754 ::sax::Converter::convertMeasure(aBuffer
, nMeasure
,
755 util::MeasureUnit::MM_100TH
, nDestUnit
);
756 aAttrValue2
= aBuffer
.makeStringAndClear();
759 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
762 case XML_ATACTION_SVG_WIDTH_HEIGHT_OASIS
:
764 OUString
aAttrValue2( aAttrValue
);
765 ReplaceSingleInWithInch( aAttrValue2
);
767 sal_Int16
const nDestUnit
= lcl_getUnit( aAttrValue2
);
770 if (::sax::Converter::convertMeasure(nMeasure
,
776 else if( nMeasure
< 0 )
780 OUStringBuffer aBuffer
;
781 ::sax::Converter::convertMeasure(aBuffer
, nMeasure
,
782 util::MeasureUnit::MM_100TH
, nDestUnit
);
783 aAttrValue2
= aBuffer
.makeStringAndClear();
786 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
789 case XML_ATACTION_DECODE_ID
:
791 const sal_Int32 nLen
= aAttrValue
.getLength();
792 OUStringBuffer aBuffer
;
795 for( pos
= 0; pos
< nLen
; pos
++ )
797 sal_Unicode c
= aAttrValue
[pos
];
798 if( (c
>= '0') && (c
<= '9') )
801 aBuffer
.append( static_cast<sal_Int32
>(c
) );
804 pMutableAttrList
->SetValueByIndex( i
, aBuffer
.makeStringAndClear() );
807 // #i50322# - special handling for the
808 // transparency of writer background graphics.
809 case XML_ATACTION_WRITER_BACK_GRAPHIC_TRANSPARENCY
:
811 // determine, if it's the transparency of a document style
812 XMLTransformerContext
* pFirstContext
= m_vContexts
[0].get();
813 OUString aFirstContextLocalName
;
814 /* sal_uInt16 nFirstContextPrefix = */
815 GetNamespaceMap().GetKeyByAttrName( pFirstContext
->GetQName(),
816 &aFirstContextLocalName
);
817 bool bIsDocumentStyle(
818 ::xmloff::token::IsXMLToken( aFirstContextLocalName
,
819 XML_DOCUMENT_STYLES
) );
820 // no conversion of transparency value for document
821 // styles, because former OpenOffice.org version writes
822 // writes always a transparency value of 100% and doesn't
823 // read the value. Thus, it's interpreted as 0%
824 if ( !bIsDocumentStyle
)
826 OUString
aAttrValue2( aAttrValue
);
827 NegPercent(aAttrValue2
);
828 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
833 case XML_ATACTION_SHAPEID
:
835 OUString sNewValue
= "shape" + aAttrValue
;
836 pMutableAttrList
->SetValueByIndex( i
, sNewValue
);
841 OSL_ENSURE( false, "unknown action" );
847 OUString
aNewAttrQName(
848 GetNamespaceMap().GetQNameByKey(
849 (*aIter
).second
.GetQNamePrefixFromParam1(),
850 ::xmloff::token::GetXMLToken(
851 (*aIter
).second
.GetQNameTokenFromParam1()) ) );
852 pMutableAttrList
->RenameAttributeByIndex( i
,
859 return pMutableAttrList
.get();
862 bool XMLTransformerBase::ReplaceSingleInchWithIn( OUString
& rValue
)
865 sal_Int32 nPos
= rValue
.getLength();
866 while( nPos
&& rValue
[nPos
-1] <= ' ' )
869 ('c'==rValue
[nPos
-2] || 'C'==rValue
[nPos
-2]) &&
870 ('h'==rValue
[nPos
-1] || 'H'==rValue
[nPos
-1]) )
872 rValue
=rValue
.copy( 0, nPos
-2 );
879 bool XMLTransformerBase::ReplaceInchWithIn( OUString
& rValue
)
883 while( nPos
< rValue
.getLength()-3 )
885 sal_Unicode c
= rValue
[nPos
];
886 if( 'i'==c
|| 'I'==c
)
889 if( (c
>= '0' && c
<= '9') || '.' == c
)
892 if( 'n'==c
|| 'N'==c
)
895 if( 'c'==c
|| 'C'==c
)
898 if( 'h'==c
|| 'H'==c
)
900 rValue
= rValue
.replaceAt( nPos
,
901 4, GetXMLToken(XML_IN
) );
916 bool XMLTransformerBase::ReplaceSingleInWithInch( OUString
& rValue
)
920 sal_Int32 nPos
= rValue
.getLength();
921 while( nPos
&& rValue
[nPos
-1] <= ' ' )
924 ('i'==rValue
[nPos
-2] ||
925 'I'==rValue
[nPos
-2]) &&
926 ('n'==rValue
[nPos
-1] ||
927 'N'==rValue
[nPos
-1]) )
930 rValue
= rValue
.replaceAt( nPos
, rValue
.getLength() - nPos
,
931 GetXMLToken(XML_INCH
) );
938 bool XMLTransformerBase::ReplaceInWithInch( OUString
& rValue
)
942 while( nPos
< rValue
.getLength()-1 )
944 sal_Unicode c
= rValue
[nPos
];
945 if( 'i'==c
|| 'I'==c
)
948 if( (c
>= '0' && c
<= '9') || '.' == c
)
951 if( 'n'==c
|| 'N'==c
)
953 rValue
= rValue
.replaceAt( nPos
,
954 2, GetXMLToken(XML_INCH
) );
967 bool XMLTransformerBase::EncodeStyleName( OUString
& rName
) const
969 static const char aHexTab
[] = "0123456789abcdef";
971 bool bEncoded
= false;
973 sal_Int32 nLen
= rName
.getLength();
974 OUStringBuffer
aBuffer( nLen
);
976 for( sal_Int32 i
= 0; i
< nLen
; i
++ )
978 sal_Unicode c
= rName
[i
];
979 bool bValidChar
= false;
983 (c
>= 0x0041 && c
<= 0x005a) ||
984 (c
>= 0x0061 && c
<= 0x007a) ||
985 (c
>= 0x00c0 && c
<= 0x00d6) ||
986 (c
>= 0x00d8 && c
<= 0x00f6) ||
987 (c
>= 0x00f8 && c
<= 0x00ff) ||
988 ( i
> 0 && ( (c
>= 0x0030 && c
<= 0x0039) ||
989 c
== 0x00b7 || c
== '-' || c
== '.') );
993 if( (c
>= 0xf900U
&& c
<= 0xfffeU
) ||
994 (c
>= 0x20ddU
&& c
<= 0x20e0U
))
998 else if( (c
>= 0x02bbU
&& c
<= 0x02c1U
) || c
== 0x0559 ||
999 c
== 0x06e5 || c
== 0x06e6 )
1003 else if( c
== 0x0387 )
1009 if( !xCharClass
.is() )
1011 const_cast < XMLTransformerBase
* >(this)
1012 ->xCharClass
= CharacterClassification::create( comphelper::getProcessComponentContext() );
1014 sal_Int16 nType
= xCharClass
->getType( rName
, i
);
1018 case UnicodeType::UPPERCASE_LETTER
: // Lu
1019 case UnicodeType::LOWERCASE_LETTER
: // Ll
1020 case UnicodeType::TITLECASE_LETTER
: // Lt
1021 case UnicodeType::OTHER_LETTER
: // Lo
1022 case UnicodeType::LETTER_NUMBER
: // Nl
1025 case UnicodeType::NON_SPACING_MARK
: // Ms
1026 case UnicodeType::ENCLOSING_MARK
: // Me
1027 case UnicodeType::COMBINING_SPACING_MARK
: //Mc
1028 case UnicodeType::MODIFIER_LETTER
: // Lm
1029 case UnicodeType::DECIMAL_DIGIT_NUMBER
: // Nd
1037 aBuffer
.append( c
);
1041 aBuffer
.append( '_' );
1043 aBuffer
.append( static_cast< sal_Unicode
>(
1044 aHexTab
[ (c
>> 12) & 0x0f ] ) );
1046 aBuffer
.append( static_cast< sal_Unicode
>(
1047 aHexTab
[ (c
>> 8) & 0x0f ] ) );
1049 aBuffer
.append( static_cast< sal_Unicode
>(
1050 aHexTab
[ (c
>> 4) & 0x0f ] ) );
1052 OUString::number(static_cast< sal_Unicode
>( aHexTab
[ c
& 0x0f ] ) )
1058 if( aBuffer
.getLength() > (1<<15)-1 )
1062 rName
= aBuffer
.makeStringAndClear();
1066 bool XMLTransformerBase::DecodeStyleName( OUString
& rName
)
1068 bool bEncoded
= false;
1070 sal_Int32 nLen
= rName
.getLength();
1071 OUStringBuffer
aBuffer( nLen
);
1073 bool bWithinHex
= false;
1074 sal_Unicode cEnc
= 0;
1075 for( sal_Int32 i
= 0; i
< nLen
; i
++ )
1077 sal_Unicode c
= rName
[i
];
1082 aBuffer
.append( cEnc
);
1089 bWithinHex
= !bWithinHex
;
1091 else if( bWithinHex
)
1094 if( c
>= '0' && c
<= '9' )
1098 else if( c
>= 'a' && c
<= 'f' )
1100 cDigit
= c
- 'a' + 10;
1102 else if( c
>= 'A' && c
<= 'F' )
1104 cDigit
= c
- 'A' + 10;
1112 cEnc
= (cEnc
<< 4) + cDigit
;
1116 aBuffer
.append( c
);
1121 rName
= aBuffer
.makeStringAndClear();
1125 bool XMLTransformerBase::NegPercent( OUString
& rValue
)
1132 sal_Int32 nLen
= rValue
.getLength();
1135 while( nPos
< nLen
&& ' ' == rValue
[nPos
] )
1138 if( nPos
< nLen
&& '-' == rValue
[nPos
] )
1145 while( nPos
< nLen
&&
1146 '0' <= rValue
[nPos
] &&
1147 '9' >= rValue
[nPos
] )
1149 // TODO: check overflow!
1151 nVal
+= (rValue
[nPos
] - '0');
1154 if( nPos
< nLen
&& '.' == rValue
[nPos
] )
1159 while( nPos
< nLen
&&
1160 '0' <= rValue
[nPos
] &&
1161 '9' >= rValue
[nPos
] )
1163 // TODO: check overflow!
1165 nVal
+= ( static_cast<double>(rValue
[nPos
] - '0') / nDiv
);
1171 while( nPos
< nLen
&& ' ' == rValue
[nPos
] )
1174 if( nPos
< nLen
&& '%' == rValue
[nPos
] )
1180 sal_Int32 nIntVal
= 100 - static_cast<sal_Int32
>( nVal
);
1182 rValue
= OUString::number(nIntVal
) + "%";
1190 void XMLTransformerBase::AddNamespacePrefix( OUString
& rName
,
1191 sal_uInt16 nPrefix
) const
1193 rName
= GetNamespaceMap().GetQNameByKey( nPrefix
, rName
, false );
1196 bool XMLTransformerBase::RemoveNamespacePrefix( OUString
& rName
,
1197 sal_uInt16 nPrefixOnly
) const
1199 OUString aLocalName
;
1200 sal_uInt16 nPrefix
=
1201 GetNamespaceMap().GetKeyByAttrValueQName(rName
, &aLocalName
);
1202 bool bRet
= XML_NAMESPACE_UNKNOWN
!= nPrefix
&&
1203 (USHRT_MAX
== nPrefixOnly
|| nPrefix
== nPrefixOnly
);
1210 bool XMLTransformerBase::ConvertURIToOASIS( OUString
& rURI
,
1211 bool bSupportPackage
) const
1214 if( !m_aExtPathPrefix
.isEmpty() && !rURI
.isEmpty() )
1221 // for package URIs, the '#' has to be removed
1222 if( bSupportPackage
)
1224 rURI
= rURI
.copy( 1 );
1229 // no rel path; nothing to do
1232 // a rel path; to keep URI simple, remove './', if there
1234 if( rURI
.getLength() > 1 && '/' == rURI
[1] )
1236 rURI
= rURI
.copy( 2 );
1241 // check for a RFC2396 schema
1245 sal_Int32 nLen
= rURI
.getLength();
1246 while( nPos
< nLen
)
1248 switch( rURI
[nPos
] )
1251 // a relative path segment
1252 nPos
= nLen
; // leave loop
1257 nPos
= nLen
; // leave loop
1260 // we don't care about any other characters
1270 rURI
= m_aExtPathPrefix
+ rURI
;
1278 bool XMLTransformerBase::ConvertURIToOOo( OUString
& rURI
,
1279 bool bSupportPackage
) const
1282 if( !rURI
.isEmpty() )
1284 bool bPackage
= false;
1288 // no rel path; nothing to do
1292 if( rURI
.startsWith( m_aExtPathPrefix
) )
1294 // an external URI; remove '../'
1295 rURI
= rURI
.copy( m_aExtPathPrefix
.getLength() );
1304 // check for a RFC2396 schema
1308 sal_Int32 nLen
= rURI
.getLength();
1309 while( nPos
< nLen
)
1311 switch( rURI
[nPos
] )
1314 // a relative path segment within the package
1315 nPos
= nLen
- 1; // leave loop
1320 nPos
= nLen
- 1; // leave loop
1323 // we don't care about any other characters
1331 if( bPackage
&& bSupportPackage
)
1333 if( rURI
.startsWith( "./" ) )
1334 rURI
= rURI
.copy( 2 );
1343 bool XMLTransformerBase::RenameAttributeValue(
1344 OUString
& rOutAttributeValue
,
1349 return ( lcl_ConvertAttr( rOutAttributeValue
, nParam1
) ||
1350 lcl_ConvertAttr( rOutAttributeValue
, nParam2
) ||
1351 lcl_ConvertAttr( rOutAttributeValue
, nParam3
) );
1355 bool XMLTransformerBase::ConvertRNGDateTimeToISO( OUString
& rDateTime
)
1357 if( !rDateTime
.isEmpty() &&
1358 rDateTime
.indexOf( '.' ) != -1 )
1360 rDateTime
= rDateTime
.replace( '.', ',');
1367 XMLTokenEnum
XMLTransformerBase::GetToken( const OUString
& rStr
) const
1369 XMLTransformerTokenMap::const_iterator aIter
=
1370 m_TokenMap
.find( rStr
);
1371 if( aIter
== m_TokenMap
.end() )
1372 return XML_TOKEN_END
;
1374 return (*aIter
).second
;
1378 const XMLTransformerContext
*XMLTransformerBase::GetCurrentContext() const
1380 OSL_ENSURE( !m_vContexts
.empty(), "empty stack" );
1383 return m_vContexts
.empty() ? nullptr : m_vContexts
.back().get();
1386 const XMLTransformerContext
*XMLTransformerBase::GetAncestorContext(
1387 sal_uInt32 n
) const
1389 auto nSize
= m_vContexts
.size();
1391 OSL_ENSURE( nSize
> n
+ 2 , "invalid context" );
1393 return nSize
> n
+ 2 ? m_vContexts
[nSize
- (n
+ 2)].get() : nullptr;
1396 bool XMLTransformerBase::isWriter() const
1398 Reference
< XServiceInfo
> xSI( mxModel
, UNO_QUERY
);
1400 ( xSI
->supportsService(u
"com.sun.star.text.TextDocument"_ustr
) ||
1401 xSI
->supportsService(u
"com.sun.star.text.WebDocument"_ustr
) ||
1402 xSI
->supportsService(u
"com.sun.star.text.GlobalDocument"_ustr
) );
1405 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */