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