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 "EventOASISTContext.hxx"
31 #include "EventMap.hxx"
32 #include "MutableAttrList.hxx"
33 #include "xmloff/xmlnmspe.hxx"
34 #include "ActionMapTypesOASIS.hxx"
35 #include "AttrTransformerAction.hxx"
36 #include "TransformerActions.hxx"
37 #ifndef _XMLOFF_TRANSFORMERBASE_HXX
38 #include "TransformerBase.hxx"
39 #endif
40 
41 #ifndef OASIS_FILTER_OOO_1X
42 // Used to parse Scripting Framework URLs
43 #include <com/sun/star/uri/XUriReferenceFactory.hpp>
44 #include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
45 #include <comphelper/processfactory.hxx>
46 #endif
47 
48 #include <hash_map>
49 
50 using ::rtl::OUString;
51 
52 using namespace ::com::sun::star::uno;
53 using namespace ::com::sun::star::xml::sax;
54 using namespace ::xmloff::token;
55 
56 class XMLTransformerOASISEventMap_Impl:
57 	public ::std::hash_map< NameKey_Impl, ::rtl::OUString,
58 						    NameHash_Impl, NameHash_Impl >
59 {
60 public:
61 	XMLTransformerOASISEventMap_Impl( XMLTransformerEventMapEntry *pInit );
62 	~XMLTransformerOASISEventMap_Impl();
63 };
64 
65 XMLTransformerOASISEventMap_Impl::XMLTransformerOASISEventMap_Impl( XMLTransformerEventMapEntry *pInit )
66 {
67 	if( pInit )
68 	{
69 		XMLTransformerOASISEventMap_Impl::key_type aKey;
70 		XMLTransformerOASISEventMap_Impl::data_type aData;
71 		while( pInit->m_pOASISName )
72 		{
73 			aKey.m_nPrefix = pInit->m_nOASISPrefix;
74 			aKey.m_aLocalName = OUString::createFromAscii(pInit->m_pOASISName);
75 
76 			OSL_ENSURE( find( aKey ) == end(), "duplicate event map entry" );
77 
78 			aData = OUString::createFromAscii(pInit->m_pOOoName);
79 
80 			XMLTransformerOASISEventMap_Impl::value_type aVal( aKey, aData );
81 
82 			insert( aVal );
83 			++pInit;
84 		}
85 	}
86 }
87 
88 XMLTransformerOASISEventMap_Impl::~XMLTransformerOASISEventMap_Impl()
89 {
90 }
91 
92 // -----------------------------------------------------------------------------
93 
94 TYPEINIT1( XMLEventOASISTransformerContext, XMLRenameElemTransformerContext);
95 
96 XMLEventOASISTransformerContext::XMLEventOASISTransformerContext(
97 		XMLTransformerBase& rImp,
98 		const OUString& rQName ) :
99 	XMLRenameElemTransformerContext( rImp, rQName,
100 		 rImp.GetNamespaceMap().GetKeyByAttrName( rQName ), XML_EVENT )
101 {
102 }
103 
104 XMLEventOASISTransformerContext::~XMLEventOASISTransformerContext()
105 {
106 }
107 
108 XMLTransformerOASISEventMap_Impl
109 	*XMLEventOASISTransformerContext::CreateEventMap()
110 {
111 	return new XMLTransformerOASISEventMap_Impl( aTransformerEventMap );
112 }
113 
114 XMLTransformerOASISEventMap_Impl
115 	*XMLEventOASISTransformerContext::CreateFormEventMap()
116 {
117 	return new XMLTransformerOASISEventMap_Impl( aFormTransformerEventMap );
118 }
119 
120 void XMLEventOASISTransformerContext::FlushEventMap(
121 		XMLTransformerOASISEventMap_Impl *p )
122 {
123 	delete p;
124 }
125 
126 OUString XMLEventOASISTransformerContext::GetEventName(
127 		sal_uInt16 nPrefix,
128 		const OUString& rName,
129 	   	XMLTransformerOASISEventMap_Impl& rMap,
130 	   	XMLTransformerOASISEventMap_Impl *pMap2)
131 {
132 	XMLTransformerOASISEventMap_Impl::key_type aKey( nPrefix, rName );
133 	if( pMap2 )
134 	{
135 		XMLTransformerOASISEventMap_Impl::const_iterator aIter =
136 			pMap2->find( aKey );
137 		if( !(aIter == pMap2->end()) )
138 			return (*aIter).second;
139 	}
140 
141 	XMLTransformerOASISEventMap_Impl::const_iterator aIter = rMap.find( aKey );
142 	if( aIter == rMap.end() )
143 		return rName;
144 	else
145 		return (*aIter).second;
146 }
147 
148 bool ParseURLAsString(
149 	const OUString& rAttrValue,
150 	OUString* pName, OUString* pLocation )
151 {
152 	OUString SCHEME( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.script:" ) );
153 
154 	sal_Int32 params = rAttrValue.indexOf( '?' );
155 	if ( rAttrValue.indexOf( SCHEME ) != 0 || params < 0 )
156 	{
157 		return sal_False;
158 	}
159 
160 	sal_Int32 start = SCHEME.getLength();
161 	*pName = rAttrValue.copy( start, params - start );
162 
163 	OUString aToken;
164 	OUString aLanguage;
165 	params++;
166 	do
167 	{
168 		aToken = rAttrValue.getToken( 0, '&', params );
169 		sal_Int32 dummy = 0;
170 
171 		if ( aToken.match( GetXMLToken( XML_LANGUAGE ) ) )
172 		{
173 			aLanguage = aToken.getToken( 1, '=', dummy );
174 		}
175 		else if ( aToken.match( GetXMLToken( XML_LOCATION ) ) )
176 		{
177 			OUString tmp = aToken.getToken( 1, '=', dummy );
178 			if ( tmp.equalsIgnoreAsciiCase( GetXMLToken( XML_DOCUMENT ) ) )
179 			{
180 				*pLocation = GetXMLToken( XML_DOCUMENT );
181 			}
182 			else
183 			{
184 				*pLocation = GetXMLToken( XML_APPLICATION );
185 			}
186 		}
187 	} while ( params >= 0 );
188 
189 	if ( aLanguage.equalsIgnoreAsciiCaseAscii( "basic" ) )
190 	{
191 		return sal_True;
192 	}
193 	return sal_False;
194 }
195 
196 bool ParseURL(
197 	const OUString& rAttrValue,
198 	OUString* pName, OUString* pLocation )
199 {
200 #ifdef OASIS_FILTER_OOO_1X
201 	return ParseURLAsString( rAttrValue, pName, pLocation );
202 #else
203 	Reference< com::sun::star::lang::XMultiServiceFactory >
204 		xSMgr = ::comphelper::getProcessServiceFactory();
205 
206 	Reference< com::sun::star::uri::XUriReferenceFactory >
207 		xFactory( xSMgr->createInstance( OUString::createFromAscii(
208 			"com.sun.star.uri.UriReferenceFactory" ) ), UNO_QUERY );
209 
210 	if ( xFactory.is() )
211 	{
212 		Reference< com::sun::star::uri::XVndSunStarScriptUrl > xUrl (
213 			xFactory->parse( rAttrValue ), UNO_QUERY );
214 
215 		if ( xUrl.is() )
216 		{
217 			OUString aLanguageKey = GetXMLToken( XML_LANGUAGE );
218 			if ( xUrl.is() && xUrl->hasParameter( aLanguageKey ) )
219 			{
220 				OUString aLanguage = xUrl->getParameter( aLanguageKey );
221 
222 				if ( aLanguage.equalsIgnoreAsciiCaseAscii( "basic" ) )
223 				{
224 					*pName = xUrl->getName();
225 
226 					OUString tmp =
227 						xUrl->getParameter( GetXMLToken( XML_LOCATION ) );
228 
229 					OUString doc = GetXMLToken( XML_DOCUMENT );
230 
231 					if ( tmp.equalsIgnoreAsciiCase( doc ) )
232 					{
233 						*pLocation = doc;
234 					}
235 					else
236 					{
237 						*pLocation = GetXMLToken( XML_APPLICATION );
238 					}
239 					return sal_True;
240 				}
241 			}
242 		}
243 		return sal_False;
244 	}
245 	else
246 	{
247 		return ParseURLAsString( rAttrValue, pName, pLocation );
248 	}
249 #endif
250 }
251 
252 void XMLEventOASISTransformerContext::StartElement(
253 	const Reference< XAttributeList >& rAttrList )
254 {
255 	OSL_TRACE("XMLEventOASISTransformerContext::StartElement");
256 
257 	XMLTransformerActions *pActions =
258 		GetTransformer().GetUserDefinedActions( OASIS_EVENT_ACTIONS );
259 	OSL_ENSURE( pActions, "go no actions" );
260 
261 	Reference< XAttributeList > xAttrList( rAttrList );
262 	XMLMutableAttributeList *pMutableAttrList = 0;
263 	sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
264 	for( sal_Int16 i=0; i < nAttrCount; i++ )
265 	{
266 		const OUString& rAttrName = xAttrList->getNameByIndex( i );
267 		OUString aLocalName;
268 		sal_uInt16 nPrefix =
269 			GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName,
270 																 &aLocalName );
271 		XMLTransformerActions::key_type aKey( nPrefix, aLocalName );
272 		XMLTransformerActions::const_iterator aIter =
273 			pActions->find( aKey );
274 		if( !(aIter == pActions->end() ) )
275 		{
276 			if( !pMutableAttrList )
277 			{
278 				pMutableAttrList =
279 						new XMLMutableAttributeList( xAttrList );
280 				xAttrList = pMutableAttrList;
281 			}
282 			const OUString& rAttrValue = xAttrList->getValueByIndex( i );
283 			switch( (*aIter).second.m_nActionType )
284 			{
285 			case XML_ATACTION_HREF:
286 				{
287 					OUString aAttrValue( rAttrValue );
288 					OUString aName, aLocation;
289 
290 					bool bNeedsTransform =
291 						ParseURL( rAttrValue, &aName, &aLocation );
292 
293 					if ( bNeedsTransform )
294 					{
295 						pMutableAttrList->RemoveAttributeByIndex( i );
296 
297 						OUString aAttrQName(
298 							GetTransformer().GetNamespaceMap().GetQNameByKey(
299 								XML_NAMESPACE_SCRIPT,
300 							::xmloff::token::GetXMLToken( XML_MACRO_NAME ) ) );
301 
302 						pMutableAttrList->AddAttribute( aAttrQName, aName );
303 
304 						sal_Int16 idx = pMutableAttrList->GetIndexByName(
305 							GetTransformer().GetNamespaceMap().GetQNameByKey(
306 								XML_NAMESPACE_SCRIPT,
307 							GetXMLToken( XML_LANGUAGE ) ) );
308 
309 						pMutableAttrList->SetValueByIndex( idx,
310 							OUString::createFromAscii("StarBasic") );
311 
312 						OUString aLocQName(
313 							GetTransformer().GetNamespaceMap().GetQNameByKey(
314 								XML_NAMESPACE_SCRIPT,
315 								GetXMLToken( XML_LOCATION ) ) );
316 
317 						pMutableAttrList->AddAttribute( aLocQName, aLocation );
318 					}
319 				}
320 				break;
321 			case XML_ATACTION_EVENT_NAME:
322 				{
323 					// Check if the event belongs to a form or control by
324 					// cehcking the 2nd ancestor element, f.i.:
325 					// <form:button><form:event-listeners><form:event-listener>
326 					const XMLTransformerContext *pObjContext =
327 						GetTransformer().GetAncestorContext( 1 );
328 					sal_Bool bForm = pObjContext &&
329 
330 						pObjContext->HasNamespace(XML_NAMESPACE_FORM );
331 					pMutableAttrList->SetValueByIndex( i,
332 								   GetTransformer().GetEventName( rAttrValue,
333 									  							  bForm ) );
334 				}
335 				break;
336 			case XML_ATACTION_REMOVE_NAMESPACE_PREFIX:
337 				{
338 					OUString aAttrValue( rAttrValue );
339 					sal_uInt16 nValPrefix =
340 						static_cast<sal_uInt16>((*aIter).second.m_nParam1);
341 					if( GetTransformer().RemoveNamespacePrefix(
342 								aAttrValue, nValPrefix ) )
343 						pMutableAttrList->SetValueByIndex( i, aAttrValue );
344 				}
345 				break;
346 			case XML_ATACTION_MACRO_NAME:
347             {
348                 OUString aName, aLocation;
349                 bool bNeedsTransform =
350                 ParseURL( rAttrValue, &aName, &aLocation );
351 
352                 if ( bNeedsTransform )
353                 {
354                     pMutableAttrList->SetValueByIndex( i, aName );
355 
356                     sal_Int16 idx = pMutableAttrList->GetIndexByName(
357                     GetTransformer().GetNamespaceMap().GetQNameByKey(
358                     XML_NAMESPACE_SCRIPT,
359                     GetXMLToken( XML_LANGUAGE ) ) );
360 
361                     pMutableAttrList->SetValueByIndex( idx,
362                     OUString::createFromAscii("StarBasic") );
363 
364                     OUString aLocQName(
365                     GetTransformer().GetNamespaceMap().GetQNameByKey(
366                     XML_NAMESPACE_SCRIPT,
367                     GetXMLToken( XML_LOCATION ) ) );
368 
369                     pMutableAttrList->AddAttribute( aLocQName, aLocation );
370                 }
371                 else
372                 {
373                     const OUString& rApp = GetXMLToken( XML_APPLICATION );
374                     const OUString& rDoc = GetXMLToken( XML_DOCUMENT );
375                     OUString aAttrValue;
376                     if( rAttrValue.getLength() > rApp.getLength()+1 &&
377                         rAttrValue.copy(0,rApp.getLength()).
378                             equalsIgnoreAsciiCase( rApp ) &&
379                         ':' == rAttrValue[rApp.getLength()] )
380                     {
381                         aLocation = rApp;
382                         aAttrValue = rAttrValue.copy( rApp.getLength()+1 );
383                     }
384                     else if( rAttrValue.getLength() > rDoc.getLength()+1 &&
385                              rAttrValue.copy(0,rDoc.getLength()).
386                                 equalsIgnoreAsciiCase( rDoc ) &&
387                              ':' == rAttrValue[rDoc.getLength()] )
388                     {
389                         aLocation= rDoc;
390                         aAttrValue = rAttrValue.copy( rDoc.getLength()+1 );
391                     }
392                     if( aAttrValue.getLength() )
393                         pMutableAttrList->SetValueByIndex( i,
394                     aAttrValue );
395                     if( aLocation.getLength() )
396                     {
397                         OUString aAttrQName( GetTransformer().GetNamespaceMap().
398                         GetQNameByKey( XML_NAMESPACE_SCRIPT,
399                         ::xmloff::token::GetXMLToken( XML_LOCATION ) ) );
400                         pMutableAttrList->AddAttribute( aAttrQName, aLocation );
401                         // draw bug
402                         aAttrQName = GetTransformer().GetNamespaceMap().
403                         GetQNameByKey( XML_NAMESPACE_SCRIPT,
404                         ::xmloff::token::GetXMLToken( XML_LIBRARY ) );
405                         pMutableAttrList->AddAttribute( aAttrQName, aLocation );
406                     }
407                 }
408             }
409             break;
410 			case XML_ATACTION_COPY:
411 				break;
412 			default:
413 				OSL_ENSURE( !this, "unknown action" );
414 				break;
415 			}
416 		}
417 	}
418 
419 	XMLRenameElemTransformerContext::StartElement( xAttrList );
420 }
421