xref: /trunk/main/xmloff/source/transform/TransformerBase.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmloff.hxx"
30 #include <rtl/ref.hxx>
31 #include <rtl/ustrbuf.hxx>
32 #include <com/sun/star/i18n/XCharacterClassification.hpp>
33 #include <com/sun/star/i18n/UnicodeType.hpp>
34 #include <comphelper/processfactory.hxx>
35 #include <xmloff/nmspmap.hxx>
36 #include "xmloff/xmlnmspe.hxx"
37 #include "IgnoreTContext.hxx"
38 #include "RenameElemTContext.hxx"
39 #include "ProcAttrTContext.hxx"
40 #include "ProcAddAttrTContext.hxx"
41 #include "MergeElemTContext.hxx"
42 #include "CreateElemTContext.hxx"
43 #include "MutableAttrList.hxx"
44 #include "TransformerActions.hxx"
45 #include "ElemTransformerAction.hxx"
46 // --> OD 2005-06-29 #i50322#
47 #include "PropertyActionsOOo.hxx"
48 // <--
49 #ifndef _XMLOFF_TRANSFORMERTOKENMAP_HXX
50 #include "TransformerTokenMap.hxx"
51 #endif
52 #include <xmloff/xmluconv.hxx>
53 
54 #ifndef _XMLOFF_TRANSFORMERBASE_HXX
55 #include "TransformerBase.hxx"
56 #endif
57 #include "TContextVector.hxx"
58 
59 using ::rtl::OUString;
60 using ::rtl::OUStringBuffer;
61 using namespace ::osl;
62 using namespace ::xmloff::token;
63 using namespace ::com::sun::star::uno;
64 using namespace ::com::sun::star::beans;
65 using namespace ::com::sun::star::lang;
66 using namespace ::com::sun::star::i18n;
67 using namespace ::com::sun::star::xml::sax;
68 
69 // -----------------------------------------------------------------------------
70 
71 namespace
72 {
73 bool lcl_ConvertAttr( OUString & rOutAttribute, sal_Int32 nParam )
74 {
75     bool bResult = false;
76     enum XMLTokenEnum eTokenToRename =
77         static_cast< enum XMLTokenEnum >( nParam & 0xffff );
78     if( eTokenToRename != XML_TOKEN_INVALID &&
79         IsXMLToken( rOutAttribute, eTokenToRename ))
80     {
81         enum XMLTokenEnum eReplacementToken =
82             static_cast< enum XMLTokenEnum >( nParam >> 16 );
83         rOutAttribute = GetXMLToken( eReplacementToken );
84         bResult = true;
85     }
86     return bResult;
87 }
88 } // anonymous namespace
89 
90 // -----------------------------------------------------------------------------
91 
92 XMLTransformerContext *XMLTransformerBase::CreateContext( sal_uInt16 nPrefix,
93     const OUString& rLocalName, const OUString& rQName )
94 {
95     XMLTransformerActions::key_type aKey( nPrefix, rLocalName );
96     XMLTransformerActions::const_iterator aIter =
97         GetElemActions().find( aKey );
98 
99     if( !(aIter == GetElemActions().end()) )
100     {
101         sal_uInt32 nActionType = (*aIter).second.m_nActionType;
102         if( (nActionType & XML_ETACTION_USER_DEFINED) != 0 )
103         {
104             XMLTransformerContext *pContext =
105                 CreateUserDefinedContext( (*aIter).second,
106                                     rQName );
107             OSL_ENSURE( pContext && !pContext->IsPersistent(),
108                         "unknown or not persistent action" );
109             return pContext;
110         }
111 
112         switch( nActionType )
113         {
114         case XML_ETACTION_COPY_CONTENT:
115             return new XMLIgnoreTransformerContext( *this, rQName, sal_False,
116                                                 sal_False );
117         case XML_ETACTION_COPY:
118             return new XMLTransformerContext( *this, rQName );
119         case XML_ETACTION_RENAME_ELEM:
120             return new XMLRenameElemTransformerContext( *this, rQName,
121                     (*aIter).second.GetQNamePrefixFromParam1(),
122                     (*aIter).second.GetQNameTokenFromParam1() );
123         case XML_ETACTION_RENAME_ELEM_ADD_ATTR:
124             return new XMLRenameElemTransformerContext( *this, rQName,
125                     (*aIter).second.GetQNamePrefixFromParam1(),
126                     (*aIter).second.GetQNameTokenFromParam1(),
127                     (*aIter).second.GetQNamePrefixFromParam2(),
128                     (*aIter).second.GetQNameTokenFromParam2(),
129                     static_cast< XMLTokenEnum >( (*aIter).second.m_nParam3 ) );
130         case XML_ETACTION_RENAME_ELEM_PROC_ATTRS:
131             return new XMLProcAttrTransformerContext( *this, rQName,
132                     (*aIter).second.GetQNamePrefixFromParam1(),
133                     (*aIter).second.GetQNameTokenFromParam1(),
134                     static_cast< sal_uInt16 >( (*aIter).second.m_nParam2 ) );
135         case XML_ETACTION_RENAME_ELEM_ADD_PROC_ATTR:
136             return new XMLProcAddAttrTransformerContext( *this, rQName,
137                     (*aIter).second.GetQNamePrefixFromParam1(),
138                     (*aIter).second.GetQNameTokenFromParam1(),
139                     static_cast< sal_uInt16 >(
140                         (*aIter).second.m_nParam3  >> 16 ),
141                     (*aIter).second.GetQNamePrefixFromParam2(),
142                     (*aIter).second.GetQNameTokenFromParam2(),
143                     static_cast< XMLTokenEnum >(
144                         (*aIter).second.m_nParam3 & 0xffff ) );
145         case XML_ETACTION_RENAME_ELEM_COND:
146             {
147                 const XMLTransformerContext *pCurrent = GetCurrentContext();
148                 if( pCurrent->HasQName(
149                             (*aIter).second.GetQNamePrefixFromParam2(),
150                             (*aIter).second.GetQNameTokenFromParam2() ) )
151                     return new XMLRenameElemTransformerContext( *this, rQName,
152                             (*aIter).second.GetQNamePrefixFromParam1(),
153                             (*aIter).second.GetQNameTokenFromParam1() );
154             }
155             break;
156         case XML_ETACTION_RENAME_ELEM_PROC_ATTRS_COND:
157             {
158                 const XMLTransformerContext *pCurrent = GetCurrentContext();
159                 if( pCurrent->HasQName(
160                             (*aIter).second.GetQNamePrefixFromParam3(),
161                             (*aIter).second.GetQNameTokenFromParam3() ) )
162                     return new XMLProcAttrTransformerContext( *this, rQName,
163                             (*aIter).second.GetQNamePrefixFromParam1(),
164                             (*aIter).second.GetQNameTokenFromParam1(),
165                             static_cast< sal_uInt16 >( (*aIter).second.m_nParam2 ) );
166                 else
167                     return new XMLProcAttrTransformerContext( *this, rQName,
168                             static_cast< sal_uInt16 >( (*aIter).second.m_nParam2 ) );
169             }
170         case XML_ETACTION_PROC_ATTRS:
171             return new XMLProcAttrTransformerContext( *this, rQName,
172                     static_cast< sal_uInt16 >( (*aIter).second.m_nParam1 ) );
173         case XML_ETACTION_PROC_ATTRS_COND:
174             {
175                 const XMLTransformerContext *pCurrent = GetCurrentContext();
176                 if( pCurrent->HasQName(
177                             (*aIter).second.GetQNamePrefixFromParam1(),
178                             (*aIter).second.GetQNameTokenFromParam1() ) )
179                     return new XMLProcAttrTransformerContext( *this, rQName,
180                             static_cast< sal_uInt16 >( (*aIter).second.m_nParam2 ) );
181             }
182             break;
183         case XML_ETACTION_MOVE_ATTRS_TO_ELEMS:
184             return new XMLCreateElemTransformerContext( *this, rQName,
185                     static_cast< sal_uInt16 >( (*aIter).second.m_nParam1 ) );
186         case XML_ETACTION_MOVE_ELEMS_TO_ATTRS:
187             return new XMLMergeElemTransformerContext( *this, rQName,
188                     static_cast< sal_uInt16 >( (*aIter).second.m_nParam1 ) );
189         default:
190             OSL_ENSURE( !this, "unknown action" );
191             break;
192         }
193     }
194 
195     // default is copying
196     return new XMLTransformerContext( *this, rQName );
197 }
198 
199 XMLTransformerActions *XMLTransformerBase::GetUserDefinedActions( sal_uInt16 )
200 {
201     return 0;
202 }
203 
204 XMLTransformerBase::XMLTransformerBase( XMLTransformerActionInit *pInit,
205                                     ::xmloff::token::XMLTokenEnum *pTKMapInit )
206     throw () :
207     m_pNamespaceMap( new SvXMLNamespaceMap ),
208     m_pReplaceNamespaceMap( new SvXMLNamespaceMap ),
209     m_pContexts( new XMLTransformerContextVector ),
210     m_pElemActions( new XMLTransformerActions( pInit ) ),
211     m_pTokenMap( new XMLTransformerTokenMap( pTKMapInit ) )
212 {
213     GetNamespaceMap().Add( GetXMLToken(XML_NP_XLINK), GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK );
214     GetNamespaceMap().Add( GetXMLToken(XML_NP_DC), GetXMLToken(XML_N_DC), XML_NAMESPACE_DC );
215     GetNamespaceMap().Add( GetXMLToken(XML_NP_MATH), GetXMLToken(XML_N_MATH), XML_NAMESPACE_MATH );
216     GetNamespaceMap().Add( GetXMLToken(XML_NP_OOO), GetXMLToken(XML_N_OOO), XML_NAMESPACE_OOO );
217     GetNamespaceMap().Add( GetXMLToken(XML_NP_DOM), GetXMLToken(XML_N_DOM), XML_NAMESPACE_DOM );
218     GetNamespaceMap().Add( GetXMLToken(XML_NP_OOOW), GetXMLToken(XML_N_OOOW), XML_NAMESPACE_OOOW );
219     GetNamespaceMap().Add( GetXMLToken(XML_NP_OOOC), GetXMLToken(XML_N_OOOC), XML_NAMESPACE_OOOC );
220 }
221 
222 XMLTransformerBase::~XMLTransformerBase() throw ()
223 {
224     ResetTokens();
225 
226     delete m_pNamespaceMap;
227     delete m_pReplaceNamespaceMap;
228     delete m_pContexts;
229     delete m_pElemActions;
230     delete m_pTokenMap;
231 }
232 
233 void SAL_CALL XMLTransformerBase::startDocument( void )
234     throw( SAXException, RuntimeException )
235 {
236     m_xHandler->startDocument();
237 }
238 
239 void SAL_CALL XMLTransformerBase::endDocument( void )
240     throw( SAXException, RuntimeException)
241 {
242     m_xHandler->endDocument();
243 }
244 
245 void SAL_CALL XMLTransformerBase::startElement( const OUString& rName,
246                                          const Reference< XAttributeList >& rAttrList )
247     throw(SAXException, RuntimeException)
248 {
249     SvXMLNamespaceMap *pRewindMap = 0;
250 
251     bool bRect = rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "presentation:show-shape" ) );
252     (void)bRect;
253 
254     // Process namespace attributes. This must happen before creating the
255     // context, because namespace decaration apply to the element name itself.
256     XMLMutableAttributeList *pMutableAttrList = 0;
257     Reference< XAttributeList > xAttrList( rAttrList );
258     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
259     for( sal_Int16 i=0; i < nAttrCount; i++ )
260     {
261         const OUString& rAttrName = xAttrList->getNameByIndex( i );
262         if( ( rAttrName.getLength() >= 5 ) &&
263             ( rAttrName.compareTo( GetXMLToken(XML_XMLNS), 5 ) == 0 ) &&
264             ( rAttrName.getLength() == 5 || ':' == rAttrName[5] ) )
265         {
266             if( !pRewindMap )
267             {
268                 pRewindMap = m_pNamespaceMap;
269                 m_pNamespaceMap = new SvXMLNamespaceMap( *m_pNamespaceMap );
270             }
271             const OUString& rAttrValue = xAttrList->getValueByIndex( i );
272 
273             OUString aPrefix( ( rAttrName.getLength() == 5 )
274                                  ? OUString()
275                                  : rAttrName.copy( 6 ) );
276             // Add namespace, but only if it is known.
277             sal_uInt16 nKey = m_pNamespaceMap->AddIfKnown( aPrefix, rAttrValue );
278             // If namespace is unknwon, try to match a name with similar
279             // TC Id an version
280             if( XML_NAMESPACE_UNKNOWN == nKey  )
281             {
282                 OUString aTestName( rAttrValue );
283                 if( SvXMLNamespaceMap::NormalizeOasisURN( aTestName ) )
284                     nKey = m_pNamespaceMap->AddIfKnown( aPrefix, aTestName );
285             }
286             // If that namespace is not known, too, add it as unknown
287             if( XML_NAMESPACE_UNKNOWN == nKey  )
288                 nKey = m_pNamespaceMap->Add( aPrefix, rAttrValue );
289 
290             const OUString& rRepName = m_pReplaceNamespaceMap->GetNameByKey( nKey );
291             if( rRepName.getLength() )
292             {
293                 if( !pMutableAttrList )
294                 {
295                     pMutableAttrList = new XMLMutableAttributeList( xAttrList );
296                     xAttrList = pMutableAttrList;
297                 }
298 
299                 pMutableAttrList->SetValueByIndex( i, rRepName );
300             }
301         }
302     }
303 
304     // Get element's namespace and local name.
305     OUString aLocalName;
306     sal_uInt16 nPrefix =
307         m_pNamespaceMap->GetKeyByAttrName( rName, &aLocalName );
308 
309     // If there are contexts already, call a CreateChildContext at the topmost
310     // context. Otherwise, create a default context.
311     ::rtl::Reference < XMLTransformerContext > xContext;
312     if( !m_pContexts->empty() )
313     {
314         xContext = m_pContexts->back()->CreateChildContext( nPrefix,
315                                                           aLocalName,
316                                                           rName,
317                                                           xAttrList );
318     }
319     else
320     {
321         xContext = CreateContext( nPrefix, aLocalName, rName );
322     }
323 
324     OSL_ENSURE( xContext.is(), "XMLTransformerBase::startElement: missing context" );
325     if( !xContext.is() )
326         xContext = new XMLTransformerContext( *this, rName );
327 
328     // Remeber old namespace map.
329     if( pRewindMap )
330         xContext->SetRewindMap( pRewindMap );
331 
332     // Push context on stack.
333     m_pContexts->push_back( xContext );
334 
335     // Call a startElement at the new context.
336     xContext->StartElement( xAttrList );
337 }
338 
339 void SAL_CALL XMLTransformerBase::endElement( const OUString&
340 #ifdef DBG_UTIL
341 rName
342 #endif
343 )
344     throw(SAXException, RuntimeException)
345 {
346     if( !m_pContexts->empty() )
347     {
348         // Get topmost context
349         ::rtl::Reference< XMLTransformerContext > xContext = m_pContexts->back();
350 
351 #ifdef DBG_UTIL
352         OSL_ENSURE( xContext->GetQName() == rName,
353                 "XMLTransformerBase::endElement: popped context has wrong lname" );
354 #endif
355 
356         // Call a EndElement at the current context.
357         xContext->EndElement();
358 
359         // and remove it from the stack.
360         m_pContexts->pop_back();
361 
362         // Get a namespace map to rewind.
363         SvXMLNamespaceMap *pRewindMap = xContext->GetRewindMap();
364 
365         // Delete the current context.
366         xContext = 0;
367 
368         // Rewind a namespace map.
369         if( pRewindMap )
370         {
371             delete m_pNamespaceMap;
372             m_pNamespaceMap = pRewindMap;
373         }
374     }
375 }
376 
377 void SAL_CALL XMLTransformerBase::characters( const OUString& rChars )
378     throw(SAXException, RuntimeException)
379 {
380     if( !m_pContexts->empty() )
381     {
382         m_pContexts->back()->Characters( rChars );
383     }
384 }
385 
386 void SAL_CALL XMLTransformerBase::ignorableWhitespace( const OUString& rWhitespaces )
387     throw(SAXException, RuntimeException)
388 {
389     m_xHandler->ignorableWhitespace( rWhitespaces );
390 }
391 
392 void SAL_CALL XMLTransformerBase::processingInstruction( const OUString& rTarget,
393                                        const OUString& rData )
394     throw(SAXException, RuntimeException)
395 {
396     m_xHandler->processingInstruction( rTarget, rData );
397 }
398 
399 void SAL_CALL XMLTransformerBase::setDocumentLocator( const Reference< XLocator >& rLocator )
400     throw(SAXException, RuntimeException)
401 {
402     m_xLocator = rLocator;
403 }
404 
405 // XExtendedDocumentHandler
406 void SAL_CALL XMLTransformerBase::startCDATA( void ) throw(SAXException, RuntimeException)
407 {
408     if( m_xExtHandler.is() )
409         m_xExtHandler->startCDATA();
410 }
411 
412 void SAL_CALL XMLTransformerBase::endCDATA( void ) throw(RuntimeException)
413 {
414     if( m_xExtHandler.is() )
415         m_xExtHandler->endCDATA();
416 }
417 
418 void SAL_CALL XMLTransformerBase::comment( const OUString& rComment )
419     throw(SAXException, RuntimeException)
420 {
421     if( m_xExtHandler.is() )
422         m_xExtHandler->comment( rComment );
423 }
424 
425 void SAL_CALL XMLTransformerBase::allowLineBreak( void )
426     throw(SAXException, RuntimeException)
427 {
428     if( m_xExtHandler.is() )
429         m_xExtHandler->allowLineBreak();
430 }
431 
432 void SAL_CALL XMLTransformerBase::unknown( const OUString& rString )
433     throw(SAXException, RuntimeException)
434 {
435     if( m_xExtHandler.is() )
436         m_xExtHandler->unknown( rString );
437 }
438 
439 // XInitialize
440 void SAL_CALL XMLTransformerBase::initialize( const Sequence< Any >& aArguments )
441     throw(Exception, RuntimeException)
442 {
443     const sal_Int32 nAnyCount = aArguments.getLength();
444     const Any* pAny = aArguments.getConstArray();
445 
446     for( sal_Int32 nIndex = 0; nIndex < nAnyCount; nIndex++, pAny++ )
447     {
448         // #b6236750# use isAssignableFrom instead of comparing the types to
449         // allow XExtendedDocumentHandler instead of XDocumentHandler (used in
450         // writeOasis2OOoLibraryElement in sfx2).
451         // The Any shift operator can't be used to query the type because it
452         // uses queryInterface, and the model also has a XPropertySet interface.
453 
454         // document handler
455         if( ::getCppuType( (const Reference< XDocumentHandler >*) 0 ).isAssignableFrom( pAny->getValueType() ) )
456             m_xHandler.set( *pAny, UNO_QUERY );
457 
458         // property set to transport data across
459         if( ::getCppuType( (const Reference< XPropertySet >*) 0 ).isAssignableFrom( pAny->getValueType() ) )
460             m_xPropSet.set( *pAny, UNO_QUERY );
461 
462         // xmodel
463         if( ::getCppuType( (const Reference< ::com::sun::star::frame::XModel >*) 0 ).isAssignableFrom( pAny->getValueType() ) )
464             mxModel.set( *pAny, UNO_QUERY );
465     }
466 
467     if( m_xPropSet.is() )
468     {
469         Any aAny;
470         OUString sRelPath, sName;
471         Reference< XPropertySetInfo > xPropSetInfo =
472             m_xPropSet->getPropertySetInfo();
473         OUString sPropName( RTL_CONSTASCII_USTRINGPARAM("StreamRelPath" ) );
474         if( xPropSetInfo->hasPropertyByName(sPropName) )
475         {
476             aAny = m_xPropSet->getPropertyValue(sPropName);
477             aAny >>= sRelPath;
478         }
479         sPropName = OUString( RTL_CONSTASCII_USTRINGPARAM("StreamName" ) );
480         if( xPropSetInfo->hasPropertyByName(sPropName) )
481         {
482             aAny = m_xPropSet->getPropertyValue(sPropName);
483             aAny >>= sName;
484         }
485         if( sName.getLength() )
486         {
487             m_aExtPathPrefix = OUString( RTL_CONSTASCII_USTRINGPARAM("../" ) );
488 
489             // If there is a rel path within a package, then append
490             // additional '../'. If the rel path contains an ':', then it is
491             // an absolute URI (or invalid URI, because zip files don't
492             // permit ':'), and it will be ignored.
493             if( sRelPath.getLength() )
494             {
495                 sal_Int32 nColPos = sRelPath.indexOf( ':' );
496                 OSL_ENSURE( -1 == nColPos,
497                             "StreamRelPath contains ':', absolute URI?" );
498 
499                 if( -1 == nColPos )
500                 {
501                     OUString sTmp = m_aExtPathPrefix;
502                     sal_Int32 nPos = 0;
503                     do
504                     {
505                         m_aExtPathPrefix += sTmp;
506                         nPos = sRelPath.indexOf( '/', nPos + 1 );
507                     }
508                     while( -1 != nPos );
509                 }
510             }
511 
512         }
513     }
514 }
515 
516 static MapUnit lcl_getUnit( const OUString& rValue )
517 {
518     MapUnit nDestUnit;
519     if( rValue.endsWithIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "cm" ) ) )
520         nDestUnit = MAP_CM;
521     else if ( rValue.endsWithIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "mm" ) ) )
522         nDestUnit = MAP_MM;
523     else
524         nDestUnit = MAP_INCH;
525     return nDestUnit;
526 }
527 
528 XMLMutableAttributeList *XMLTransformerBase::ProcessAttrList(
529         Reference< XAttributeList >& rAttrList, sal_uInt16 nActionMap,
530         sal_Bool bClone )
531 {
532     XMLMutableAttributeList *pMutableAttrList = 0;
533     XMLTransformerActions *pActions = GetUserDefinedActions( nActionMap );
534     OSL_ENSURE( pActions, "go no actions" );
535     if( pActions )
536     {
537         sal_Int16 nAttrCount = rAttrList.is() ? rAttrList->getLength() : 0;
538         for( sal_Int16 i=0; i < nAttrCount; ++i )
539         {
540             const OUString& rAttrName = rAttrList->getNameByIndex( i );
541             const OUString& rAttrValue = rAttrList->getValueByIndex( i );
542             OUString aLocalName;
543             sal_uInt16 nPrefix = GetNamespaceMap().GetKeyByAttrName( rAttrName,
544                                                            &aLocalName );
545 
546             XMLTransformerActions::key_type aKey( nPrefix, aLocalName );
547             XMLTransformerActions::const_iterator aIter =
548                     pActions->find( aKey );
549             if( !(aIter == pActions->end() ) )
550             {
551                 if( !pMutableAttrList )
552                 {
553                     pMutableAttrList = new XMLMutableAttributeList( rAttrList,
554                                                                     bClone );
555                     rAttrList = pMutableAttrList;
556                 }
557 
558                 sal_uInt32 nAction = (*aIter).second.m_nActionType;
559                 sal_Bool bRename = sal_False;
560                 switch( nAction )
561                 {
562                 case XML_ATACTION_RENAME:
563                     bRename = sal_True;
564                     break;
565                 case XML_ATACTION_COPY:
566                     break;
567                 case XML_ATACTION_REMOVE:
568                 case XML_ATACTION_STYLE_DISPLAY_NAME:
569                     pMutableAttrList->RemoveAttributeByIndex( i );
570                     --i;
571                     --nAttrCount;
572                     break;
573                 case XML_ATACTION_RENAME_IN2INCH:
574                     bRename = sal_True;
575                 case XML_ATACTION_IN2INCH:
576                     {
577                         OUString aAttrValue( rAttrValue );
578                         if( ReplaceSingleInWithInch( aAttrValue ) )
579                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
580                     }
581                     break;
582                 case XML_ATACTION_INS2INCHS:
583                     {
584                         OUString aAttrValue( rAttrValue );
585                         if( ReplaceInWithInch( aAttrValue ) )
586                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
587                     }
588                     break;
589                 case XML_ATACTION_RENAME_INCH2IN:
590                     bRename = sal_True;
591                 case XML_ATACTION_INCH2IN:
592                     {
593                         OUString aAttrValue( rAttrValue );
594                         if( ReplaceSingleInchWithIn( aAttrValue ) )
595                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
596                     }
597                     break;
598                 case XML_ATACTION_INCHS2INS:
599                     {
600                         OUString aAttrValue( rAttrValue );
601                         if( ReplaceInchWithIn( aAttrValue ) )
602                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
603                     }
604                     break;
605                 case XML_ATACTION_TWIPS2IN:
606                     {
607                         OUString aAttrValue( rAttrValue );
608 
609                         XMLTransformerBase::ReplaceSingleInchWithIn( aAttrValue );
610                         if( isWriter() )
611                         {
612                             MapUnit nDestUnit = lcl_getUnit( aAttrValue );
613 
614                             // convert twips value to inch
615                             sal_Int32 nMeasure;
616                             if( SvXMLUnitConverter::convertMeasure(nMeasure, aAttrValue, MAP_100TH_MM ) )
617                             {
618 
619                                 // --> OD 2004-10-29 #i13778#,#i36248#
620                                 // apply correct twip-to-1/100mm
621                                 nMeasure = (sal_Int32)( nMeasure >= 0
622                                                         ? ((nMeasure*127+36)/72)
623                                                         : ((nMeasure*127-36)/72) );
624                                 // <--
625 
626                                 rtl::OUStringBuffer aBuffer;
627                                 SvXMLUnitConverter::convertMeasure( aBuffer, nMeasure, MAP_100TH_MM, nDestUnit );
628                                 aAttrValue = aBuffer.makeStringAndClear();
629                             }
630                         }
631 
632                         pMutableAttrList->SetValueByIndex( i, aAttrValue );
633                     }
634                     break;
635                 case XML_ATACTION_RENAME_DECODE_STYLE_NAME_REF:
636                     bRename = sal_True;
637                 case XML_ATACTION_DECODE_STYLE_NAME:
638                 case XML_ATACTION_DECODE_STYLE_NAME_REF:
639                     {
640                         OUString aAttrValue( rAttrValue );
641                         if( DecodeStyleName(aAttrValue) )
642                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
643                     }
644                     break;
645                 case XML_ATACTION_ENCODE_STYLE_NAME:
646                     {
647                         OUString aAttrValue( rAttrValue );
648                         if( EncodeStyleName(aAttrValue) )
649                         {
650                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
651                             OUString aNewAttrQName(
652                                 GetNamespaceMap().GetQNameByKey(
653                                     nPrefix,
654                                 ::xmloff::token::GetXMLToken(
655                                 XML_DISPLAY_NAME ) ) );
656                             pMutableAttrList->AddAttribute( aNewAttrQName,
657                                                             rAttrValue );
658                         }
659                     }
660                     break;
661                 case XML_ATACTION_RENAME_ENCODE_STYLE_NAME_REF:
662                     bRename = sal_True;
663                 case XML_ATACTION_ENCODE_STYLE_NAME_REF:
664                     {
665                         OUString aAttrValue( rAttrValue );
666                         if( EncodeStyleName(aAttrValue) )
667                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
668                     }
669                     break;
670                 case XML_ATACTION_RENAME_NEG_PERCENT:
671                     bRename = sal_True;
672                 case XML_ATACTION_NEG_PERCENT:
673                     {
674                         OUString aAttrValue( rAttrValue );
675                         if( NegPercent( aAttrValue ) )
676                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
677                     }
678                     break;
679                 case XML_ATACTION_RENAME_ADD_NAMESPACE_PREFIX:
680                     bRename = sal_True;
681                 case XML_ATACTION_ADD_NAMESPACE_PREFIX:
682                     {
683                         OUString aAttrValue( rAttrValue );
684                         sal_uInt16 nValPrefix =
685                             static_cast<sal_uInt16>(
686                                     bRename ? (*aIter).second.m_nParam2
687                                             : (*aIter).second.m_nParam1);
688                         if( AddNamespacePrefix( aAttrValue, nValPrefix ) )
689                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
690                     }
691                     break;
692                 case XML_ATACTION_ADD_APP_NAMESPACE_PREFIX:
693                     {
694                         OUString aAttrValue( rAttrValue );
695                         sal_uInt16 nValPrefix =
696                             static_cast<sal_uInt16>((*aIter).second.m_nParam1);
697                         if( IsXMLToken( GetClass(), XML_SPREADSHEET  ) )
698                             nValPrefix = XML_NAMESPACE_OOOC;
699                         else if( IsXMLToken( GetClass(), XML_TEXT  ) )
700                             nValPrefix = XML_NAMESPACE_OOOW;
701                         if( AddNamespacePrefix( aAttrValue, nValPrefix ) )
702                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
703                     }
704                     break;
705                 case XML_ATACTION_RENAME_REMOVE_NAMESPACE_PREFIX:
706                     bRename = sal_True;
707                 case XML_ATACTION_REMOVE_NAMESPACE_PREFIX:
708                     {
709                         OUString aAttrValue( rAttrValue );
710                         sal_uInt16 nValPrefix =
711                             static_cast<sal_uInt16>(
712                                     bRename ? (*aIter).second.m_nParam2
713                                             : (*aIter).second.m_nParam1);
714                         if( RemoveNamespacePrefix( aAttrValue, nValPrefix ) )
715                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
716                     }
717                     break;
718                 case XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX:
719                     {
720                         OUString aAttrValue( rAttrValue );
721                         if( RemoveNamespacePrefix( aAttrValue ) )
722                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
723                     }
724                     break;
725                 case XML_ATACTION_URI_OOO:
726                     {
727                         OUString aAttrValue( rAttrValue );
728                         if( ConvertURIToOASIS( aAttrValue,
729                             static_cast< sal_Bool >((*aIter).second.m_nParam1)))
730                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
731                     }
732                     break;
733                 case XML_ATACTION_URI_OASIS:
734                     {
735                         OUString aAttrValue( rAttrValue );
736                         if( ConvertURIToOOo( aAttrValue,
737                             static_cast< sal_Bool >((*aIter).second.m_nParam1)))
738                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
739                     }
740                     break;
741                 case XML_ATACTION_RENAME_ATTRIBUTE:
742                     {
743                         OUString aAttrValue( rAttrValue );
744                         RenameAttributeValue(
745                             aAttrValue,
746                             (*aIter).second.m_nParam1,
747                             (*aIter).second.m_nParam2,
748                             (*aIter).second.m_nParam3 );
749                         pMutableAttrList->SetValueByIndex( i, aAttrValue );
750                     }
751                     break;
752                 case XML_ATACTION_RNG2ISO_DATETIME:
753                     {
754                         OUString aAttrValue( rAttrValue );
755                         if( ConvertRNGDateTimeToISO( aAttrValue ))
756                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
757                     }
758                     break;
759                 case XML_ATACTION_RENAME_RNG2ISO_DATETIME:
760                     {
761                         OUString aAttrValue( rAttrValue );
762                         if( ConvertRNGDateTimeToISO( aAttrValue ))
763                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
764                         bRename = sal_True;
765                     }
766                     break;
767                 case XML_ATACTION_IN2TWIPS:
768                     {
769                         OUString aAttrValue( rAttrValue );
770                         XMLTransformerBase::ReplaceSingleInWithInch( aAttrValue );
771 
772                         if( isWriter() )
773                         {
774                             MapUnit nDestUnit = lcl_getUnit( aAttrValue );
775 
776                             // convert inch value to twips and export as faked inch
777                             sal_Int32 nMeasure;
778                             if( SvXMLUnitConverter::convertMeasure(nMeasure, aAttrValue, MAP_100TH_MM ) )
779                             {
780 
781                                 // --> OD 2004-10-29 #i13778#,#i36248#
782                                 // apply correct 1/100mm-to-twip conversion
783                                 nMeasure = (sal_Int32)( nMeasure >= 0
784                                                         ? ((nMeasure*72+63)/127)
785                                                         : ((nMeasure*72-63)/127) );
786                                 // <--
787 
788                                 OUStringBuffer aBuffer;
789                                 SvXMLUnitConverter::convertMeasure( aBuffer, nMeasure, MAP_100TH_MM, nDestUnit );
790                                 aAttrValue = aBuffer.makeStringAndClear();
791                             }
792                         }
793 
794                         pMutableAttrList->SetValueByIndex( i, aAttrValue );
795                     }
796                     break;
797                 case XML_ATACTION_SVG_WIDTH_HEIGHT_OOO:
798                     {
799                         OUString aAttrValue( rAttrValue );
800                         ReplaceSingleInchWithIn( aAttrValue );
801 
802                         MapUnit nDestUnit = lcl_getUnit( aAttrValue );
803 
804                         sal_Int32 nMeasure;
805                         if( SvXMLUnitConverter::convertMeasure(nMeasure, aAttrValue, MAP_100TH_MM ) )
806                         {
807 
808                             if( nMeasure > 0 )
809                                 nMeasure -= 1;
810                             else if( nMeasure < 0 )
811                                 nMeasure += 1;
812 
813 
814                             OUStringBuffer aBuffer;
815                             SvXMLUnitConverter::convertMeasure( aBuffer, nMeasure, MAP_100TH_MM, nDestUnit );
816                             aAttrValue = aBuffer.makeStringAndClear();
817                         }
818 
819                         pMutableAttrList->SetValueByIndex( i, aAttrValue );
820                     }
821                     break;
822                 case XML_ATACTION_SVG_WIDTH_HEIGHT_OASIS:
823                     {
824                         OUString aAttrValue( rAttrValue );
825                         ReplaceSingleInWithInch( aAttrValue );
826 
827                         MapUnit nDestUnit = lcl_getUnit( aAttrValue );
828 
829                         sal_Int32 nMeasure;
830                         if( SvXMLUnitConverter::convertMeasure(nMeasure, aAttrValue, MAP_100TH_MM ) )
831                         {
832 
833                             if( nMeasure > 0 )
834                                 nMeasure += 1;
835                             else if( nMeasure < 0 )
836                                 nMeasure -= 1;
837 
838 
839                             OUStringBuffer aBuffer;
840                             SvXMLUnitConverter::convertMeasure( aBuffer, nMeasure, MAP_100TH_MM, nDestUnit );
841                             aAttrValue = aBuffer.makeStringAndClear();
842                         }
843 
844                         pMutableAttrList->SetValueByIndex( i, aAttrValue );
845                     }
846                     break;
847                 case XML_ATACTION_DECODE_ID:
848                     {
849                         OUString aAttrValue;
850 
851                         const sal_Int32 nLen = rAttrValue.getLength();
852                         OUStringBuffer aBuffer;
853 
854                         sal_Int32 pos;
855                         for( pos = 0; pos < nLen; pos++ )
856                         {
857                             sal_Unicode c = rAttrValue[pos];
858                             if( (c >= '0') && (c <= '9') )
859                                 aBuffer.append( c );
860                             else
861                                 aBuffer.append( (sal_Int32)c );
862                         }
863 
864                         pMutableAttrList->SetValueByIndex( i, aBuffer.makeStringAndClear() );
865                     }
866                     break;
867                 // --> OD 2005-06-10 #i50322# - special handling for the
868                 // transparency of writer background graphics.
869                 case XML_ATACTION_WRITER_BACK_GRAPHIC_TRANSPARENCY:
870                     {
871                         // determine, if it's the transparency of a document style
872                         XMLTransformerContext* pFirstContext = (*m_pContexts)[0].get();
873                         OUString aFirstContextLocalName;
874                         /* sal_uInt16 nFirstContextPrefix = */
875                             GetNamespaceMap().GetKeyByAttrName( pFirstContext->GetQName(),
876                                                                 &aFirstContextLocalName );
877                         bool bIsDocumentStyle(
878                             ::xmloff::token::IsXMLToken( aFirstContextLocalName,
879                                                          XML_DOCUMENT_STYLES ) );
880                         // no conversion of transparency value for document
881                         // styles, because former OpenOffice.org version writes
882                         // writes always a transparency value of 100% and doesn't
883                         // read the value. Thus, it's intepreted as 0%
884                         if ( !bIsDocumentStyle )
885                         {
886                             OUString aAttrValue( rAttrValue );
887                             NegPercent(aAttrValue);
888                             pMutableAttrList->SetValueByIndex( i, aAttrValue );
889                         }
890                         bRename = sal_True;
891                     }
892                     break;
893                 // <--
894                 case XML_ATACTION_SHAPEID:
895                 {
896                     OUString sNewValue( RTL_CONSTASCII_USTRINGPARAM( "shape" ) );
897                     sNewValue += rAttrValue;
898                     pMutableAttrList->SetValueByIndex( i, sNewValue );
899                     break;
900                 }
901 
902                 default:
903                     OSL_ENSURE( !this, "unknown action" );
904                     break;
905                 }
906 
907                 if( bRename )
908                 {
909                     OUString aNewAttrQName(
910                         GetNamespaceMap().GetQNameByKey(
911                             (*aIter).second.GetQNamePrefixFromParam1(),
912                             ::xmloff::token::GetXMLToken(
913                                 (*aIter).second.GetQNameTokenFromParam1()) ) );
914                     pMutableAttrList->RenameAttributeByIndex( i,
915                                                               aNewAttrQName );
916                 }
917             }
918         }
919     }
920 
921     return pMutableAttrList;
922 }
923 
924 sal_Bool XMLTransformerBase::ReplaceSingleInchWithIn( OUString& rValue )
925 {
926     sal_Bool bRet = sal_False;
927     sal_Int32 nPos = rValue.getLength();
928     while( nPos && rValue[nPos-1] <= ' ' )
929         --nPos;
930     if( nPos > 2 &&
931         ('c'==rValue[nPos-2] || 'C'==rValue[nPos-2]) &&
932         ('h'==rValue[nPos-1] || 'H'==rValue[nPos-1]) )
933     {
934         rValue =rValue.copy( 0, nPos-2 );
935         bRet = sal_True;
936     }
937 
938     return bRet;
939 }
940 
941 sal_Bool XMLTransformerBase::ReplaceInchWithIn( OUString& rValue )
942 {
943     sal_Bool bRet = sal_False;
944     sal_Int32 nPos = 1;
945     while( nPos < rValue.getLength()-3 )
946     {
947         sal_Unicode c = rValue[nPos];
948         if( 'i'==c || 'I'==c )
949         {
950             c = rValue[nPos-1];
951             if( (c >= '0' && c <= '9') || '.' == c )
952             {
953                 c = rValue[nPos+1];
954                 if( 'n'==c || 'N'==c )
955                 {
956                     c = rValue[nPos+2];
957                     if( 'c'==c || 'C'==c )
958                     {
959                         c = rValue[nPos+3];
960                         if( 'h'==c || 'H'==c )
961                         {
962                             rValue = rValue.replaceAt( nPos,
963                                 4, GetXMLToken(XML_UNIT_INCH) );
964                             nPos += 2;
965                             bRet = sal_True;
966                             continue;
967                         }
968                     }
969                 }
970             }
971         }
972         ++nPos;
973     }
974 
975     return bRet;
976 }
977 
978 sal_Bool XMLTransformerBase::ReplaceSingleInWithInch( OUString& rValue )
979 {
980     sal_Bool bRet = sal_False;
981 
982     sal_Int32 nPos = rValue.getLength();
983     while( nPos && rValue[nPos-1] <= ' ' )
984         --nPos;
985     if( nPos > 2 &&
986         ('i'==rValue[nPos-2] ||
987             'I'==rValue[nPos-2]) &&
988         ('n'==rValue[nPos-1] ||
989             'N'==rValue[nPos-1]) )
990     {
991         nPos -= 2;
992         rValue = rValue.replaceAt( nPos, rValue.getLength() - nPos,
993                                            GetXMLToken(XML_INCH) );
994         bRet = sal_True;
995     }
996 
997     return bRet;
998 }
999 
1000 sal_Bool XMLTransformerBase::ReplaceInWithInch( OUString& rValue )
1001 {
1002     sal_Bool bRet = sal_False;
1003     sal_Int32 nPos = 1;
1004     while( nPos < rValue.getLength()-1 )
1005     {
1006         sal_Unicode c = rValue[nPos];
1007         if( 'i'==c || 'I'==c )
1008         {
1009             c = rValue[nPos-1];
1010             if( (c >= '0' && c <= '9') || '.' == c )
1011             {
1012                 c = rValue[nPos+1];
1013                 if( 'n'==c || 'N'==c )
1014                 {
1015                     rValue = rValue.replaceAt( nPos,
1016                                     2, GetXMLToken(XML_INCH) );
1017                     nPos += 4;
1018                     bRet = sal_True;
1019                     continue;
1020                 }
1021             }
1022         }
1023         ++nPos;
1024     }
1025 
1026     return bRet;
1027 }
1028 
1029 sal_Bool XMLTransformerBase::EncodeStyleName( OUString& rName ) const
1030 {
1031     static sal_Char aHexTab[] = "0123456789abcdef";
1032 
1033     sal_Bool bEncoded = sal_False;
1034 
1035     sal_Int32 nLen = rName.getLength();
1036     OUStringBuffer aBuffer( nLen );
1037 
1038     for( sal_Int32 i = 0; i < nLen; i++ )
1039     {
1040         sal_Unicode c = rName[i];
1041         sal_Bool bValidChar = sal_False;
1042         if( c < 0x00ffU )
1043         {
1044             bValidChar =
1045                 (c >= 0x0041 && c <= 0x005a) ||
1046                 (c >= 0x0061 && c <= 0x007a) ||
1047                 (c >= 0x00c0 && c <= 0x00d6) ||
1048                 (c >= 0x00d8 && c <= 0x00f6) ||
1049                 (c >= 0x00f8 && c <= 0x00ff) ||
1050                 ( i > 0 && ( (c >= 0x0030 && c <= 0x0039) ||
1051                              c == 0x00b7 || c == '-' || c == '.') );
1052         }
1053         else
1054         {
1055             if( (c >= 0xf900U && c <= 0xfffeU) ||
1056                 (c >= 0x20ddU && c <= 0x20e0U))
1057             {
1058                 bValidChar = sal_False;
1059             }
1060             else if( (c >= 0x02bbU && c <= 0x02c1U) || c == 0x0559 ||
1061                      c == 0x06e5 || c == 0x06e6 )
1062             {
1063                 bValidChar = sal_True;
1064             }
1065             else if( c == 0x0387 )
1066             {
1067                 bValidChar = i > 0;
1068             }
1069             else
1070             {
1071                 if( !xCharClass.is() )
1072                 {
1073                     Reference< XMultiServiceFactory > xFactory =
1074                         comphelper::getProcessServiceFactory();
1075                     if( xFactory.is() )
1076                     {
1077                         try
1078                         {
1079                             const_cast < XMLTransformerBase * >(this)
1080                                 ->xCharClass =
1081                                     Reference < XCharacterClassification >(
1082                                 xFactory->createInstance(
1083                                     OUString::createFromAscii(
1084                         "com.sun.star.i18n.CharacterClassification_Unicode") ),
1085                                 UNO_QUERY );
1086 
1087                             OSL_ENSURE( xCharClass.is(),
1088                     "can't instantiate character clossification component" );
1089                         }
1090                         catch( com::sun::star::uno::Exception& )
1091                         {
1092                         }
1093                     }
1094                 }
1095                 if( xCharClass.is() )
1096                 {
1097                     sal_Int16 nType = xCharClass->getType( rName, i );
1098 
1099                     switch( nType )
1100                     {
1101                     case UnicodeType::UPPERCASE_LETTER:     // Lu
1102                     case UnicodeType::LOWERCASE_LETTER:     // Ll
1103                     case UnicodeType::TITLECASE_LETTER:     // Lt
1104                     case UnicodeType::OTHER_LETTER:         // Lo
1105                     case UnicodeType::LETTER_NUMBER:        // Nl
1106                         bValidChar = sal_True;
1107                         break;
1108                     case UnicodeType::NON_SPACING_MARK:     // Ms
1109                     case UnicodeType::ENCLOSING_MARK:       // Me
1110                     case UnicodeType::COMBINING_SPACING_MARK:   //Mc
1111                     case UnicodeType::MODIFIER_LETTER:      // Lm
1112                     case UnicodeType::DECIMAL_DIGIT_NUMBER: // Nd
1113                         bValidChar = i > 0;
1114                         break;
1115                     }
1116                 }
1117             }
1118         }
1119         if( bValidChar )
1120         {
1121             aBuffer.append( c );
1122         }
1123         else
1124         {
1125             aBuffer.append( static_cast< sal_Unicode >( '_' ) );
1126             if( c > 0x0fff )
1127                 aBuffer.append( static_cast< sal_Unicode >(
1128                             aHexTab[ (c >> 12) & 0x0f ]  ) );
1129             if( c > 0x00ff )
1130                 aBuffer.append( static_cast< sal_Unicode >(
1131                         aHexTab[ (c >> 8) & 0x0f ] ) );
1132             if( c > 0x000f )
1133                 aBuffer.append( static_cast< sal_Unicode >(
1134                         aHexTab[ (c >> 4) & 0x0f ] ) );
1135             aBuffer.append( static_cast< sal_Unicode >(
1136                         aHexTab[ c & 0x0f ] ) );
1137             aBuffer.append( static_cast< sal_Unicode >( '_' ) );
1138             bEncoded = sal_True;
1139         }
1140     }
1141 
1142     if( aBuffer.getLength() > (1<<15)-1 )
1143         bEncoded = sal_False;
1144 
1145     if( bEncoded )
1146         rName = aBuffer.makeStringAndClear();
1147     return bEncoded;
1148 }
1149 
1150 sal_Bool XMLTransformerBase::DecodeStyleName( OUString& rName )
1151 {
1152     sal_Bool bEncoded = sal_False;
1153 
1154     sal_Int32 nLen = rName.getLength();
1155     OUStringBuffer aBuffer( nLen );
1156 
1157     sal_Bool bWithinHex = sal_False;
1158     sal_Unicode cEnc = 0;
1159     for( sal_Int32 i = 0; i < nLen; i++ )
1160     {
1161         sal_Unicode c = rName[i];
1162         if( '_' == c )
1163         {
1164             if( bWithinHex )
1165             {
1166                 aBuffer.append( cEnc );
1167                 cEnc = 0;
1168             }
1169             else
1170             {
1171                 bEncoded = sal_True;
1172             }
1173             bWithinHex = !bWithinHex;
1174         }
1175         else if( bWithinHex )
1176         {
1177             sal_Unicode cDigit;
1178             if( c >= '0' && c <= '9' )
1179             {
1180                 cDigit = c - '0';
1181             }
1182             else if( c >= 'a' && c <= 'f' )
1183             {
1184                 cDigit = c - 'a' + 10;
1185             }
1186             else if( c >= 'A' && c <= 'F' )
1187             {
1188                 cDigit = c - 'A' + 10;
1189             }
1190             else
1191             {
1192                 // error
1193                 bEncoded = sal_False;
1194                 break;
1195             }
1196             cEnc = (cEnc << 4) + cDigit;
1197         }
1198         else
1199         {
1200             aBuffer.append( c );
1201         }
1202     }
1203 
1204     if( bEncoded )
1205         rName = aBuffer.makeStringAndClear();
1206     return bEncoded;
1207 }
1208 
1209 sal_Bool XMLTransformerBase::NegPercent( OUString& rValue )
1210 {
1211     sal_Bool bRet = sal_False;
1212     sal_Bool bNeg = sal_False;
1213     double nVal = 0;
1214 
1215     sal_Int32 nPos = 0;
1216     sal_Int32 nLen = rValue.getLength();
1217 
1218     // skip white space
1219     while( nPos < nLen && sal_Unicode(' ') == rValue[nPos] )
1220         nPos++;
1221 
1222     if( nPos < nLen && sal_Unicode('-') == rValue[nPos] )
1223     {
1224         bNeg = sal_True;
1225         nPos++;
1226     }
1227 
1228     // get number
1229     while( nPos < nLen &&
1230            sal_Unicode('0') <= rValue[nPos] &&
1231            sal_Unicode('9') >= rValue[nPos] )
1232     {
1233         // TODO: check overflow!
1234         nVal *= 10;
1235         nVal += (rValue[nPos] - sal_Unicode('0'));
1236         nPos++;
1237     }
1238     double nDiv = 1.;
1239     if( nPos < nLen && sal_Unicode('.') == rValue[nPos] )
1240     {
1241         nPos++;
1242 
1243         while( nPos < nLen &&
1244                sal_Unicode('0') <= rValue[nPos] &&
1245                sal_Unicode('9') >= rValue[nPos] )
1246         {
1247             // TODO: check overflow!
1248             nDiv *= 10;
1249             nVal += ( static_cast<double>(rValue[nPos] - sal_Unicode('0')) / nDiv );
1250             nPos++;
1251         }
1252     }
1253 
1254     // skip white space
1255     while( nPos < nLen && sal_Unicode(' ') == rValue[nPos] )
1256         nPos++;
1257 
1258     if( nPos < nLen &&  sal_Unicode('%') == rValue[nPos] )
1259     {
1260         if( bNeg )
1261             nVal = -nVal;
1262         nVal += .5;
1263 
1264         sal_Int32 nIntVal = 100 - static_cast<sal_Int32>( nVal );
1265 
1266         OUStringBuffer aNewValBuffer;
1267         aNewValBuffer.append( nIntVal );
1268         aNewValBuffer.append( sal_Unicode('%' ) );
1269 
1270         rValue = aNewValBuffer.makeStringAndClear();
1271         bRet = sal_True;
1272     }
1273 
1274     return bRet;
1275 }
1276 
1277 sal_Bool XMLTransformerBase::AddNamespacePrefix( ::rtl::OUString& rName,
1278                              sal_uInt16 nPrefix ) const
1279 {
1280     rName = GetNamespaceMap().GetQNameByKey( nPrefix, rName, sal_False );
1281     return sal_True;
1282 }
1283 
1284 sal_Bool XMLTransformerBase::RemoveNamespacePrefix( ::rtl::OUString& rName,
1285                             sal_uInt16 nPrefixOnly ) const
1286 {
1287     OUString aLocalName;
1288     sal_uInt16 nPrefix =
1289         GetNamespaceMap()._GetKeyByAttrName( rName, &aLocalName, sal_False );
1290     sal_Bool bRet = XML_NAMESPACE_UNKNOWN != nPrefix &&
1291                     (USHRT_MAX == nPrefixOnly || nPrefix == nPrefixOnly);
1292     if( bRet )
1293         rName = aLocalName;
1294 
1295     return bRet;
1296 }
1297 
1298 sal_Bool XMLTransformerBase::ConvertURIToOASIS( ::rtl::OUString& rURI,
1299                                         sal_Bool bSupportPackage ) const
1300 {
1301     sal_Bool bRet = sal_False;
1302     if( m_aExtPathPrefix.getLength() && rURI.getLength() )
1303     {
1304         sal_Bool bRel = sal_False;
1305         switch( rURI[0] )
1306         {
1307         case '#':
1308             // no rel path, but
1309             // for package URIs, the '#' has to be removed
1310             if( bSupportPackage )
1311             {
1312                 rURI = rURI.copy( 1 );
1313                 bRet = sal_True;
1314             }
1315             break;
1316         case '/':
1317             // no rel path; nothing to do
1318             break;
1319         case '.':
1320             // a rel path; to keep URI simple, remove './', if there
1321             bRel = sal_True;
1322             if( rURI.getLength() > 1 && '/' == rURI[1] )
1323             {
1324                 rURI = rURI.copy( 2 );
1325                 bRet = sal_True;
1326             }
1327             break;
1328         default:
1329             // check for a RFC2396 schema
1330             {
1331                 bRel = sal_True;
1332                 sal_Int32 nPos = 1;
1333                 sal_Int32 nLen = rURI.getLength();
1334                 while( nPos < nLen )
1335                 {
1336                     switch( rURI[nPos] )
1337                     {
1338                     case '/':
1339                         // a relative path segement
1340                         nPos = nLen;    // leave loop
1341                         break;
1342                     case ':':
1343                         // a schema
1344                         bRel = sal_False;
1345                         nPos = nLen;    // leave loop
1346                         break;
1347                     default:
1348                         // we don't care about any other characters
1349                         break;
1350                     }
1351                     ++nPos;
1352                 }
1353             }
1354         }
1355 
1356         if( bRel )
1357         {
1358             OUString sTmp( m_aExtPathPrefix );
1359             sTmp += rURI;
1360             rURI = sTmp;
1361             bRet = sal_True;
1362         }
1363     }
1364 
1365     return bRet;
1366 }
1367 
1368 sal_Bool XMLTransformerBase::ConvertURIToOOo( ::rtl::OUString& rURI,
1369                                         sal_Bool bSupportPackage ) const
1370 {
1371     sal_Bool bRet = sal_False;
1372     if( rURI.getLength() )
1373     {
1374         sal_Bool bPackage = sal_False;
1375         switch( rURI[0] )
1376         {
1377         case '/':
1378             // no rel path; nothing to to
1379             break;
1380         case '.':
1381             // a rel path
1382             if( 0 == rURI.compareTo( m_aExtPathPrefix,
1383                                      m_aExtPathPrefix.getLength() ) )
1384             {
1385                 // an external URI; remove '../'
1386                 rURI = rURI.copy( m_aExtPathPrefix.getLength() );
1387                 bRet = sal_True;
1388             }
1389             else
1390             {
1391                 bPackage = sal_True;
1392             }
1393             break;
1394         default:
1395             // check for a RFC2396 schema
1396             {
1397                 bPackage = sal_True;
1398                 sal_Int32 nPos = 1;
1399                 sal_Int32 nLen = rURI.getLength();
1400                 while( nPos < nLen )
1401                 {
1402                     switch( rURI[nPos] )
1403                     {
1404                     case '/':
1405                         // a relative path segement within the package
1406                         nPos = nLen;    // leave loop
1407                         break;
1408                     case ':':
1409                         // a schema
1410                         bPackage = sal_False;
1411                         nPos = nLen;    // leave loop
1412                         break;
1413                     default:
1414                         // we don't care about any other characters
1415                         break;
1416                     }
1417                     ++nPos;
1418                 }
1419             }
1420         }
1421 
1422         if( bPackage && bSupportPackage )
1423         {
1424             OUString sTmp( OUString::valueOf( sal_Unicode( '#' ) ) );
1425             if( 0 == rURI.compareToAscii( "./", 2 ) )
1426                 rURI = rURI.copy( 2 );
1427             sTmp += rURI;
1428             rURI = sTmp;
1429             bRet = sal_True;
1430         }
1431     }
1432 
1433     return bRet;
1434 }
1435 
1436 sal_Bool XMLTransformerBase::RenameAttributeValue(
1437     OUString& rOutAttributeValue,
1438     sal_Int32 nParam1,
1439     sal_Int32 nParam2,
1440     sal_Int32 nParam3 )
1441 {
1442     return ( lcl_ConvertAttr( rOutAttributeValue, nParam1) ||
1443              lcl_ConvertAttr( rOutAttributeValue, nParam2) ||
1444              lcl_ConvertAttr( rOutAttributeValue, nParam3) );
1445 }
1446 
1447 // static
1448 bool XMLTransformerBase::ConvertRNGDateTimeToISO( ::rtl::OUString& rDateTime )
1449 {
1450     if( rDateTime.getLength() > 0 &&
1451         rDateTime.indexOf( sal_Unicode('.')) != -1 )
1452     {
1453         rDateTime = rDateTime.replace( sal_Unicode('.'), sal_Unicode(','));
1454         return true;
1455     }
1456 
1457     return false;
1458 }
1459 
1460 XMLTokenEnum XMLTransformerBase::GetToken( const OUString& rStr ) const
1461 {
1462     XMLTransformerTokenMap::const_iterator aIter =
1463         m_pTokenMap->find( rStr );
1464     if( aIter == m_pTokenMap->end() )
1465         return XML_TOKEN_END;
1466     else
1467         return (*aIter).second;
1468 }
1469 
1470 
1471 
1472 const XMLTransformerContext *XMLTransformerBase::GetCurrentContext() const
1473 {
1474     OSL_ENSURE( !m_pContexts->empty(), "empty stack" );
1475 
1476 
1477     return m_pContexts->empty() ? 0 : m_pContexts->back().get();
1478 }
1479 
1480 const XMLTransformerContext *XMLTransformerBase::GetAncestorContext(
1481                                                         sal_uInt32 n ) const
1482 {
1483     XMLTransformerContextVector::size_type nSize =
1484         m_pContexts->size();
1485     XMLTransformerContextVector::size_type nPos =
1486         static_cast<XMLTransformerContextVector::size_type>( n );
1487 
1488     OSL_ENSURE( nSize >nPos+2 , "invalid context" );
1489 
1490     return nSize > nPos+2 ? (*m_pContexts)[nSize-(nPos+2)].get() : 0;
1491 }
1492 
1493 bool XMLTransformerBase::isWriter() const
1494 {
1495     Reference< XServiceInfo > xSI( mxModel, UNO_QUERY );
1496     return  xSI.is() &&
1497         (   xSI->supportsService( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.text.TextDocument" ) ) ) ||
1498             xSI->supportsService( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.text.WebDocument" ) ) ) ||
1499             xSI->supportsService( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.text.GlobalDocument" ) ) ) );
1500 }
1501