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