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 {
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 
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( sal_False, "unknown action" );
187 			break;
188 		}
189 	}
190 
191 	// default is copying
192 	return new XMLTransformerContext( *this, rQName );
193 }
194 
195 XMLTransformerActions *XMLTransformerBase::GetUserDefinedActions( sal_uInt16 )
196 {
197 	return 0;
198 }
199 
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 
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 
229 void SAL_CALL XMLTransformerBase::startDocument( void )
230 	throw( SAXException, RuntimeException )
231 {
232 	m_xHandler->startDocument();
233 }
234 
235 void SAL_CALL XMLTransformerBase::endDocument( void )
236 	throw( SAXException, RuntimeException)
237 {
238 	m_xHandler->endDocument();
239 }
240 
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 	// Remember 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 
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 
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 
382 void SAL_CALL XMLTransformerBase::ignorableWhitespace( const OUString& rWhitespaces )
383 	throw(SAXException, RuntimeException)
384 {
385 	m_xHandler->ignorableWhitespace( rWhitespaces );
386 }
387 
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 
395 void SAL_CALL XMLTransformerBase::setDocumentLocator( const Reference< XLocator >& rLocator )
396 	throw(SAXException, RuntimeException)
397 {
398 	m_xLocator = rLocator;
399 }
400 
401 // XExtendedDocumentHandler
402 void SAL_CALL XMLTransformerBase::startCDATA( void ) throw(SAXException, RuntimeException)
403 {
404 	if( m_xExtHandler.is() )
405 		m_xExtHandler->startCDATA();
406 }
407 
408 void SAL_CALL XMLTransformerBase::endCDATA( void ) throw(RuntimeException)
409 {
410 	if( m_xExtHandler.is() )
411 		m_xExtHandler->endCDATA();
412 }
413 
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 
421 void SAL_CALL XMLTransformerBase::allowLineBreak( void )
422 	throw(SAXException, RuntimeException)
423 {
424 	if( m_xExtHandler.is() )
425 		m_xExtHandler->allowLineBreak();
426 }
427 
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
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 
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 
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( sal_False, "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 
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 
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 
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 
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 
1025 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 
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 
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 
1273 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 
1280 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 
1294 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 
1364 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 
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
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 
1456 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 
1468 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 
1476 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 
1489 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