1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "EventOASISTContext.hxx"
21 #include "EventMap.hxx"
22 #include "MutableAttrList.hxx"
23 #include <xmloff/xmlnamespace.hxx>
24 #include "ActionMapTypesOASIS.hxx"
25 #include "AttrTransformerAction.hxx"
26 #include "TransformerActions.hxx"
27 #include "TransformerBase.hxx"
28 #include <osl/diagnose.h>
29 #include <sal/log.hxx>
30 #include <o3tl/string_view.hxx>
32 // Used to parse Scripting Framework URLs
33 #include <com/sun/star/uri/UriReferenceFactory.hpp>
34 #include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
35 #include <comphelper/processfactory.hxx>
37 #include <unordered_map>
39 using namespace ::com::sun::star::uno
;
40 using namespace ::com::sun::star::xml::sax
;
41 using namespace ::xmloff::token
;
43 class XMLTransformerOASISEventMap_Impl
:
44 public std::unordered_map
< NameKey_Impl
, OUString
,
45 NameHash_Impl
, NameHash_Impl
>
48 explicit XMLTransformerOASISEventMap_Impl( XMLTransformerEventMapEntry
const *pInit
);
51 XMLTransformerOASISEventMap_Impl::XMLTransformerOASISEventMap_Impl( XMLTransformerEventMapEntry
const *pInit
)
56 XMLTransformerOASISEventMap_Impl::key_type aKey
;
57 XMLTransformerOASISEventMap_Impl::mapped_type aData
;
58 while( !pInit
->m_pOASISName
.isEmpty() )
60 aKey
.m_nPrefix
= pInit
->m_nOASISPrefix
;
61 aKey
.m_aLocalName
= pInit
->m_pOASISName
;
63 OSL_ENSURE( find( aKey
) == end(), "duplicate event map entry" );
65 aData
= pInit
->m_pOOoName
;
67 XMLTransformerOASISEventMap_Impl::value_type
aVal( aKey
, aData
);
74 XMLEventOASISTransformerContext::XMLEventOASISTransformerContext(
75 XMLTransformerBase
& rImp
,
76 const OUString
& rQName
) :
77 XMLRenameElemTransformerContext( rImp
, rQName
,
78 rImp
.GetNamespaceMap().GetKeyByAttrName( rQName
), XML_EVENT
)
82 XMLEventOASISTransformerContext::~XMLEventOASISTransformerContext()
86 XMLTransformerOASISEventMap_Impl
87 *XMLEventOASISTransformerContext::CreateEventMap()
89 return new XMLTransformerOASISEventMap_Impl( aTransformerEventMap
);
92 XMLTransformerOASISEventMap_Impl
93 *XMLEventOASISTransformerContext::CreateFormEventMap()
95 return new XMLTransformerOASISEventMap_Impl( aFormTransformerEventMap
);
98 void XMLEventOASISTransformerContext::FlushEventMap(
99 XMLTransformerOASISEventMap_Impl
*p
)
104 OUString
XMLEventOASISTransformerContext::GetEventName(
106 const OUString
& rName
,
107 XMLTransformerOASISEventMap_Impl
& rMap
,
108 XMLTransformerOASISEventMap_Impl
*pMap2
)
110 XMLTransformerOASISEventMap_Impl::key_type
aKey( nPrefix
, rName
);
113 XMLTransformerOASISEventMap_Impl::const_iterator aIter
=
115 if( aIter
!= pMap2
->end() )
116 return (*aIter
).second
;
119 XMLTransformerOASISEventMap_Impl::const_iterator aIter
= rMap
.find( aKey
);
120 if( aIter
== rMap
.end() )
123 return (*aIter
).second
;
126 static bool ParseURL(
127 const OUString
& rAttrValue
,
128 OUString
* pName
, OUString
* pLocation
)
130 const Reference
< css::uno::XComponentContext
>& xContext
= ::comphelper::getProcessComponentContext();
132 Reference
< css::uri::XUriReferenceFactory
> xFactory
= css::uri::UriReferenceFactory::create(xContext
);
134 Reference
< css::uri::XVndSunStarScriptUrl
> xUrl ( xFactory
->parse( rAttrValue
), UNO_QUERY
);
138 const OUString
& aLanguageKey
= GetXMLToken( XML_LANGUAGE
);
139 if ( xUrl
.is() && xUrl
->hasParameter( aLanguageKey
) )
141 OUString aLanguage
= xUrl
->getParameter( aLanguageKey
);
143 if ( aLanguage
.equalsIgnoreAsciiCase("basic") )
145 *pName
= xUrl
->getName();
148 xUrl
->getParameter( GetXMLToken( XML_LOCATION
) );
150 const OUString
& doc
= GetXMLToken( XML_DOCUMENT
);
152 if ( tmp
.equalsIgnoreAsciiCase( doc
) )
158 *pLocation
= GetXMLToken( XML_APPLICATION
);
167 void XMLEventOASISTransformerContext::StartElement(
168 const Reference
< XAttributeList
>& rAttrList
)
170 SAL_INFO("xmloff.transform", "XMLEventOASISTransformerContext::StartElement");
172 XMLTransformerActions
*pActions
=
173 GetTransformer().GetUserDefinedActions( OASIS_EVENT_ACTIONS
);
174 SAL_WARN_IF( pActions
== nullptr, "xmloff.transform", "got no actions" );
176 Reference
< XAttributeList
> xAttrList( rAttrList
);
177 rtl::Reference
<XMLMutableAttributeList
> pMutableAttrList
;
178 sal_Int16 nAttrCount
= xAttrList
.is() ? xAttrList
->getLength() : 0;
179 for( sal_Int16 i
=0; i
< nAttrCount
; i
++ )
181 const OUString aAttrName
= xAttrList
->getNameByIndex( i
);
184 GetTransformer().GetNamespaceMap().GetKeyByAttrName( aAttrName
,
186 XMLTransformerActions::key_type
aKey( nPrefix
, aLocalName
);
187 XMLTransformerActions::const_iterator aIter
=
188 pActions
->find( aKey
);
189 if( aIter
!= pActions
->end() )
191 if( !pMutableAttrList
)
194 new XMLMutableAttributeList( xAttrList
);
195 xAttrList
= pMutableAttrList
;
197 const OUString aAttrValue
= xAttrList
->getValueByIndex( i
);
198 switch( (*aIter
).second
.m_nActionType
)
200 case XML_ATACTION_HREF
:
202 OUString aName
, aLocation
;
204 bool bNeedsTransform
=
205 ParseURL( aAttrValue
, &aName
, &aLocation
);
207 if ( bNeedsTransform
)
209 pMutableAttrList
->RemoveAttributeByIndex( i
);
212 GetTransformer().GetNamespaceMap().GetQNameByKey(
213 XML_NAMESPACE_SCRIPT
,
214 ::xmloff::token::GetXMLToken( XML_MACRO_NAME
) ) );
216 pMutableAttrList
->AddAttribute( aAttrQName
, aName
);
218 sal_Int16 idx
= pMutableAttrList
->GetIndexByName(
219 GetTransformer().GetNamespaceMap().GetQNameByKey(
220 XML_NAMESPACE_SCRIPT
,
221 GetXMLToken( XML_LANGUAGE
) ) );
224 pMutableAttrList
->SetValueByIndex(idx
, u
"StarBasic"_ustr
);
227 GetTransformer().GetNamespaceMap().GetQNameByKey(
228 XML_NAMESPACE_SCRIPT
,
229 GetXMLToken( XML_LOCATION
) ) );
231 pMutableAttrList
->AddAttribute( aLocQName
, aLocation
);
235 case XML_ATACTION_EVENT_NAME
:
237 // Check if the event belongs to a form or control by
238 // checking the 2nd ancestor element, f.i.:
239 // <form:button><form:event-listeners><form:event-listener>
240 const XMLTransformerContext
*pObjContext
=
241 GetTransformer().GetAncestorContext( 1 );
242 bool bForm
= pObjContext
&&
244 pObjContext
->HasNamespace(XML_NAMESPACE_FORM
);
245 pMutableAttrList
->SetValueByIndex( i
,
246 GetTransformer().GetEventName( aAttrValue
,
250 case XML_ATACTION_REMOVE_NAMESPACE_PREFIX
:
252 OUString
aAttrValue2( aAttrValue
);
253 sal_uInt16 nValPrefix
=
254 static_cast<sal_uInt16
>((*aIter
).second
.m_nParam1
);
255 if( GetTransformer().RemoveNamespacePrefix(
256 aAttrValue2
, nValPrefix
) )
257 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
260 case XML_ATACTION_MACRO_NAME
:
262 OUString aName
, aLocation
;
263 bool bNeedsTransform
=
264 ParseURL( aAttrValue
, &aName
, &aLocation
);
266 if ( bNeedsTransform
)
268 pMutableAttrList
->SetValueByIndex( i
, aName
);
270 sal_Int16 idx
= pMutableAttrList
->GetIndexByName(
271 GetTransformer().GetNamespaceMap().GetQNameByKey(
272 XML_NAMESPACE_SCRIPT
,
273 GetXMLToken( XML_LANGUAGE
) ) );
276 pMutableAttrList
->SetValueByIndex(idx
, u
"StarBasic"_ustr
);
279 GetTransformer().GetNamespaceMap().GetQNameByKey(
280 XML_NAMESPACE_SCRIPT
,
281 GetXMLToken( XML_LOCATION
) ) );
283 pMutableAttrList
->AddAttribute( aLocQName
, aLocation
);
287 const OUString
& rApp
= GetXMLToken( XML_APPLICATION
);
288 const OUString
& rDoc
= GetXMLToken( XML_DOCUMENT
);
289 OUString aAttrValue2
;
290 if( aAttrValue
.getLength() > rApp
.getLength()+1 &&
291 o3tl::equalsIgnoreAsciiCase(aAttrValue
.subView(0,rApp
.getLength()), rApp
) &&
292 ':' == aAttrValue
[rApp
.getLength()] )
295 aAttrValue2
= aAttrValue
.copy( rApp
.getLength()+1 );
297 else if( aAttrValue
.getLength() > rDoc
.getLength()+1 &&
298 o3tl::equalsIgnoreAsciiCase(aAttrValue
.subView(0,rDoc
.getLength()), rDoc
) &&
299 ':' == aAttrValue
[rDoc
.getLength()] )
302 aAttrValue2
= aAttrValue
.copy( rDoc
.getLength()+1 );
304 if( !aAttrValue2
.isEmpty() )
305 pMutableAttrList
->SetValueByIndex( i
, aAttrValue2
);
306 if( !aLocation
.isEmpty() )
308 OUString
aAttrQName( GetTransformer().GetNamespaceMap().
309 GetQNameByKey( XML_NAMESPACE_SCRIPT
,
310 ::xmloff::token::GetXMLToken( XML_LOCATION
) ) );
311 pMutableAttrList
->AddAttribute( aAttrQName
, aLocation
);
313 aAttrQName
= GetTransformer().GetNamespaceMap().
314 GetQNameByKey( XML_NAMESPACE_SCRIPT
,
315 ::xmloff::token::GetXMLToken( XML_LIBRARY
) );
316 pMutableAttrList
->AddAttribute( aAttrQName
, aLocation
);
321 case XML_ATACTION_COPY
:
324 SAL_WARN( "xmloff.transform", "unknown action" );
330 XMLRenameElemTransformerContext::StartElement( xAttrList
);
333 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */