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