Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 : #ifdef _MSC_VER
20 : #pragma warning(disable : 4701)
21 : #endif
22 :
23 : #include "saxbuilder.hxx"
24 :
25 : #include <com/sun/star/xml/dom/DocumentBuilder.hpp>
26 : #include <comphelper/processfactory.hxx>
27 : #include <cppuhelper/supportsservice.hxx>
28 :
29 : using namespace css::lang;
30 : using namespace css::uno;
31 : using namespace css::xml::dom;
32 : using namespace css::xml::sax;
33 :
34 : namespace DOM
35 : {
36 700 : Reference< XInterface > CSAXDocumentBuilder::_getInstance(const Reference< XMultiServiceFactory >& rSMgr)
37 : {
38 700 : return static_cast< XSAXDocumentBuilder* >(new CSAXDocumentBuilder(rSMgr));
39 : }
40 :
41 : const char* CSAXDocumentBuilder::aImplementationName = "com.sun.star.comp.xml.dom.SAXDocumentBuilder";
42 : const char* CSAXDocumentBuilder::aSupportedServiceNames[] = {
43 : "com.sun.star.xml.dom.SAXDocumentBuilder",
44 : NULL
45 : };
46 :
47 700 : CSAXDocumentBuilder::CSAXDocumentBuilder(const Reference< XMultiServiceFactory >& mgr)
48 : : m_aServiceManager(mgr)
49 700 : , m_aState( SAXDocumentBuilderState_READY)
50 700 : {}
51 :
52 307 : OUString CSAXDocumentBuilder::_getImplementationName()
53 : {
54 307 : return OUString::createFromAscii(aImplementationName);
55 : }
56 73 : Sequence<OUString> CSAXDocumentBuilder::_getSupportedServiceNames()
57 : {
58 73 : Sequence<OUString> aSequence;
59 146 : for (int i=0; aSupportedServiceNames[i]!=NULL; i++) {
60 73 : aSequence.realloc(i+1);
61 73 : aSequence[i]=(OUString::createFromAscii(aSupportedServiceNames[i]));
62 : }
63 73 : return aSequence;
64 : }
65 :
66 1 : Sequence< OUString > SAL_CALL CSAXDocumentBuilder::getSupportedServiceNames()
67 : throw (RuntimeException, std::exception)
68 : {
69 1 : return CSAXDocumentBuilder::_getSupportedServiceNames();
70 : }
71 :
72 1 : OUString SAL_CALL CSAXDocumentBuilder::getImplementationName()
73 : throw (RuntimeException, std::exception)
74 : {
75 1 : return CSAXDocumentBuilder::_getImplementationName();
76 : }
77 :
78 0 : sal_Bool SAL_CALL CSAXDocumentBuilder::supportsService(const OUString& aServiceName)
79 : throw (RuntimeException, std::exception)
80 : {
81 0 : return cppu::supportsService(this, aServiceName);
82 : }
83 :
84 0 : SAXDocumentBuilderState SAL_CALL CSAXDocumentBuilder::getState()
85 : throw (RuntimeException, std::exception)
86 : {
87 0 : ::osl::MutexGuard g(m_Mutex);
88 :
89 0 : return m_aState;
90 : }
91 :
92 0 : void SAL_CALL CSAXDocumentBuilder::reset()
93 : throw (RuntimeException, std::exception)
94 : {
95 0 : ::osl::MutexGuard g(m_Mutex);
96 :
97 0 : m_aDocument.clear();
98 0 : m_aFragment.clear();
99 0 : while (!m_aNodeStack.empty()) m_aNodeStack.pop();
100 0 : while (!m_aNSStack.empty()) m_aNSStack.pop();
101 0 : m_aState = SAXDocumentBuilderState_READY;
102 0 : }
103 :
104 698 : Reference< XDocument > SAL_CALL CSAXDocumentBuilder::getDocument()
105 : throw (RuntimeException, std::exception)
106 : {
107 698 : ::osl::MutexGuard g(m_Mutex);
108 :
109 698 : if (m_aState != SAXDocumentBuilderState_DOCUMENT_FINISHED)
110 0 : throw RuntimeException();
111 :
112 698 : return m_aDocument;
113 : }
114 :
115 0 : Reference< XDocumentFragment > SAL_CALL CSAXDocumentBuilder::getDocumentFragment()
116 : throw (RuntimeException, std::exception)
117 : {
118 0 : ::osl::MutexGuard g(m_Mutex);
119 :
120 0 : if (m_aState != SAXDocumentBuilderState_FRAGMENT_FINISHED)
121 0 : throw RuntimeException();
122 0 : return m_aFragment;
123 : }
124 :
125 0 : void SAL_CALL CSAXDocumentBuilder::startDocumentFragment(const Reference< XDocument >& ownerDoc)
126 : throw (RuntimeException, std::exception)
127 : {
128 0 : ::osl::MutexGuard g(m_Mutex);
129 :
130 : // start a new document fragment and push it onto the stack
131 : // we have to be in a clean state to do this
132 0 : if (m_aState != SAXDocumentBuilderState_READY)
133 0 : throw RuntimeException();
134 :
135 0 : m_aDocument = ownerDoc;
136 0 : Reference< XDocumentFragment > aFragment = m_aDocument->createDocumentFragment();
137 0 : m_aNodeStack.push(aFragment);
138 0 : m_aFragment = aFragment;
139 0 : m_aState = SAXDocumentBuilderState_BUILDING_FRAGMENT;
140 0 : }
141 :
142 0 : void SAL_CALL CSAXDocumentBuilder::endDocumentFragment()
143 : throw (RuntimeException, std::exception)
144 : {
145 0 : ::osl::MutexGuard g(m_Mutex);
146 :
147 : // there should only be the document left on the node stack
148 0 : if (m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
149 0 : throw RuntimeException();
150 :
151 0 : Reference< XNode > aNode = m_aNodeStack.top();
152 0 : if ( aNode->getNodeType() != NodeType_DOCUMENT_FRAGMENT_NODE)
153 0 : throw RuntimeException();
154 0 : m_aNodeStack.pop();
155 0 : m_aState = SAXDocumentBuilderState_FRAGMENT_FINISHED;
156 0 : }
157 :
158 : // document handler
159 :
160 698 : void SAL_CALL CSAXDocumentBuilder::startDocument() throw (RuntimeException, SAXException, std::exception)
161 : {
162 698 : ::osl::MutexGuard g(m_Mutex);
163 :
164 : // start a new document and push it onto the stack
165 : // we have to be in a clean state to do this
166 698 : if (m_aState != SAXDocumentBuilderState_READY)
167 0 : throw SAXException();
168 :
169 1396 : Reference< XDocumentBuilder > aBuilder(DocumentBuilder::create(comphelper::getComponentContext(m_aServiceManager)));
170 1396 : Reference< XDocument > aDocument = aBuilder->newDocument();
171 698 : m_aNodeStack.push(aDocument);
172 698 : m_aDocument = aDocument;
173 1396 : m_aState = SAXDocumentBuilderState_BUILDING_DOCUMENT;
174 698 : }
175 :
176 698 : void SAL_CALL CSAXDocumentBuilder::endDocument() throw (RuntimeException, SAXException, std::exception)
177 : {
178 698 : ::osl::MutexGuard g(m_Mutex);
179 :
180 : // there should only be the document left on the node stack
181 698 : if (m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT)
182 0 : throw SAXException();
183 :
184 1396 : Reference< XNode > aNode = m_aNodeStack.top();
185 698 : if ( aNode->getNodeType() != NodeType_DOCUMENT_NODE)
186 0 : throw SAXException();
187 698 : m_aNodeStack.pop();
188 1396 : m_aState = SAXDocumentBuilderState_DOCUMENT_FINISHED;
189 698 : }
190 :
191 5381 : void SAL_CALL CSAXDocumentBuilder::startElement(const OUString& aName, const Reference< XAttributeList>& attribs)
192 : throw (RuntimeException, SAXException, std::exception)
193 : {
194 5381 : ::osl::MutexGuard g(m_Mutex);
195 :
196 5381 : if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
197 0 : m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
198 : {
199 0 : throw SAXException();
200 : }
201 :
202 : // start with mappings in effect for last level
203 10762 : NSMap aNSMap;
204 5381 : if (!m_aNSStack.empty())
205 4683 : aNSMap = NSMap(m_aNSStack.top());
206 :
207 : // handle xmlns: attributes and add to mappings
208 10762 : OUString attr_qname;
209 10762 : OUString attr_value;
210 10762 : OUString newprefix;
211 10762 : AttrMap aAttrMap;
212 5381 : sal_Int32 idx=-1;
213 5381 : sal_Int16 nAttributes = attribs->getLength();
214 16095 : for (sal_Int16 i=0; i<nAttributes; i++)
215 : {
216 10714 : attr_qname = attribs->getNameByIndex(i);
217 10714 : attr_value = attribs->getValueByIndex(i);
218 : // new prefix mapping
219 10714 : if (attr_qname.startsWith("xmlns:"))
220 : {
221 6245 : newprefix = attr_qname.copy(attr_qname.indexOf(':')+1);
222 6245 : aNSMap.insert(NSMap::value_type(newprefix, attr_value));
223 : }
224 4469 : else if ( attr_qname == "xmlns" )
225 : {
226 : // new default prefix
227 0 : aNSMap.insert(NSMap::value_type(OUString(), attr_value));
228 : }
229 : else
230 : {
231 4469 : aAttrMap.insert(AttrMap::value_type(attr_qname, attr_value));
232 : }
233 : }
234 :
235 : // does the element have a prefix?
236 10762 : OUString aPrefix;
237 10762 : OUString aURI;
238 10762 : Reference< XElement > aElement;
239 5381 : idx = aName.indexOf(':');
240 5381 : if (idx != -1)
241 : {
242 5380 : aPrefix = aName.copy(0, idx);
243 : }
244 : else
245 1 : aPrefix.clear();
246 :
247 5381 : NSMap::const_iterator result = aNSMap.find(aPrefix);
248 5381 : if ( result != aNSMap.end())
249 : {
250 : // found a URI for prefix
251 : // qualified name
252 5380 : aElement = m_aDocument->createElementNS( result->second, aName);
253 : }
254 : else
255 : {
256 : // no URI for prefix
257 1 : aElement = m_aDocument->createElement(aName);
258 : }
259 10762 : aElement = Reference< XElement > (
260 5381 : m_aNodeStack.top()->appendChild(aElement),
261 5381 : UNO_QUERY);
262 5381 : m_aNodeStack.push(aElement);
263 :
264 : // set non xmlns attributes
265 5381 : aPrefix.clear();
266 5381 : aURI.clear();
267 5381 : AttrMap::const_iterator a = aAttrMap.begin();
268 15231 : while (a != aAttrMap.end())
269 : {
270 4469 : attr_qname = a->first;
271 4469 : attr_value = a->second;
272 4469 : idx = attr_qname.indexOf(':');
273 4469 : if (idx != -1)
274 4469 : aPrefix = attr_qname.copy(0, idx);
275 : else
276 0 : aPrefix.clear();
277 :
278 4469 : result = aNSMap.find(aPrefix);
279 4469 : if (result != aNSMap.end())
280 : {
281 : // set attribute with namespace
282 4469 : aElement->setAttributeNS(result->second, attr_qname, attr_value);
283 : }
284 : else
285 : {
286 : // set attribute without namespace
287 0 : aElement->setAttribute(attr_qname, attr_value);
288 : }
289 4469 : ++a;
290 : }
291 10762 : m_aNSStack.push(aNSMap);
292 5381 : }
293 :
294 5381 : void SAL_CALL CSAXDocumentBuilder::endElement(const OUString& aName)
295 : throw (RuntimeException, SAXException, std::exception)
296 : {
297 5381 : ::osl::MutexGuard g(m_Mutex);
298 :
299 : // pop the current element from the stack
300 5381 : if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
301 0 : m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
302 0 : throw SAXException();
303 :
304 10762 : Reference< XNode > aNode(m_aNodeStack.top());
305 5381 : if (aNode->getNodeType() != NodeType_ELEMENT_NODE)
306 0 : throw SAXException();
307 :
308 10762 : Reference< XElement > aElement(aNode, UNO_QUERY);
309 10762 : OUString aRefName;
310 10762 : OUString aPrefix = aElement->getPrefix();
311 5381 : if (!aPrefix.isEmpty())
312 5380 : aRefName = aPrefix + ":" + aElement->getTagName();
313 : else
314 1 : aRefName = aElement->getTagName();
315 5381 : if (aRefName != aName) // consistency check
316 0 : throw SAXException();
317 :
318 : // pop it
319 5381 : m_aNodeStack.pop();
320 10762 : m_aNSStack.pop();
321 5381 : }
322 :
323 3473 : void SAL_CALL CSAXDocumentBuilder::characters(const OUString& aChars)
324 : throw (RuntimeException, SAXException, std::exception)
325 : {
326 3473 : ::osl::MutexGuard g(m_Mutex);
327 :
328 : // append text node to the current top element
329 3473 : if (m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
330 0 : m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
331 0 : throw SAXException();
332 :
333 6946 : Reference< XText > aText = m_aDocument->createTextNode(aChars);
334 6946 : m_aNodeStack.top()->appendChild(aText);
335 3473 : }
336 :
337 0 : void SAL_CALL CSAXDocumentBuilder::ignorableWhitespace(const OUString& )
338 : throw (RuntimeException, SAXException, std::exception)
339 : {
340 0 : ::osl::MutexGuard g(m_Mutex);
341 :
342 : // ignore ignorable whitespace
343 0 : if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
344 0 : m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
345 0 : throw SAXException();
346 0 : }
347 :
348 0 : void SAL_CALL CSAXDocumentBuilder::processingInstruction(const OUString& aTarget, const OUString& aData)
349 : throw (RuntimeException, SAXException, std::exception)
350 : {
351 0 : ::osl::MutexGuard g(m_Mutex);
352 :
353 : // append PI node to the current top
354 0 : if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
355 0 : m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
356 0 : throw SAXException();
357 :
358 0 : Reference< XProcessingInstruction > aInstruction = m_aDocument->createProcessingInstruction(
359 0 : aTarget, aData);
360 0 : m_aNodeStack.top()->appendChild(aInstruction);
361 0 : }
362 :
363 0 : void SAL_CALL CSAXDocumentBuilder::setDocumentLocator(const Reference< XLocator >& aLocator)
364 : throw (RuntimeException, SAXException, std::exception)
365 : {
366 0 : ::osl::MutexGuard g(m_Mutex);
367 :
368 : // set the document locator...
369 0 : m_aLocator = aLocator;
370 0 : }
371 : }
372 :
373 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|