Branch data 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 : :
20 : : #include <documentbuilder.hxx>
21 : :
22 : : #include <string.h>
23 : : #include <stdio.h>
24 : : #include <stdarg.h>
25 : :
26 : : #include <libxml/xmlerror.h>
27 : : #include <libxml/tree.h>
28 : :
29 : : #include <boost/shared_ptr.hpp>
30 : :
31 : : #include <rtl/alloc.h>
32 : : #include <rtl/memory.h>
33 : : #include <rtl/ustrbuf.hxx>
34 : :
35 : : #include <cppuhelper/implbase1.hxx>
36 : :
37 : : #include <com/sun/star/xml/sax/SAXParseException.hpp>
38 : : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
39 : : #include <com/sun/star/task/XInteractionHandler.hpp>
40 : :
41 : : #include <ucbhelper/content.hxx>
42 : : #include <ucbhelper/commandenvironment.hxx>
43 : :
44 : : #include <node.hxx>
45 : : #include <document.hxx>
46 : :
47 : :
48 : : using ::rtl::OUStringBuffer;
49 : : using ::rtl::OString;
50 : : using ::com::sun::star::xml::sax::InputSource;
51 : : using namespace ucbhelper;
52 : : using namespace ::com::sun::star::ucb;
53 : : using ::com::sun::star::task::XInteractionHandler;
54 : :
55 : :
56 : : namespace DOM
57 : : {
58 : :
59 [ - + ]: 573 : class CDefaultEntityResolver : public cppu::WeakImplHelper1< XEntityResolver >
60 : : {
61 : : public:
62 : 0 : virtual InputSource SAL_CALL resolveEntity( const OUString& sPublicId, const OUString& sSystemId )
63 : : throw (::com::sun::star::uno::RuntimeException)
64 : : {
65 : 0 : InputSource is;
66 : 0 : is.sPublicId = sPublicId;
67 : 0 : is.sSystemId = sSystemId;
68 : 0 : is.sEncoding = OUString();
69 : :
70 : : try {
71 : : Reference< XCommandEnvironment > aEnvironment(
72 : : new CommandEnvironment(Reference< XInteractionHandler >(),
73 [ # # ][ # # ]: 0 : Reference< XProgressHandler >() ));
[ # # ]
74 [ # # ]: 0 : Content aContent(sSystemId, aEnvironment);
75 : :
76 [ # # ][ # # ]: 0 : is.aInputStream = aContent.openStream();
[ # # ]
77 [ # # # # ]: 0 : } catch (const com::sun::star::uno::Exception&) {
78 : : OSL_FAIL("exception in default entity resolver");
79 [ # # ]: 0 : is.aInputStream = Reference< XInputStream >();
80 : : }
81 : 0 : return is;
82 : : }
83 : :
84 : : };
85 : :
86 : 191 : CDocumentBuilder::CDocumentBuilder(
87 : : Reference< XMultiServiceFactory > const& xFactory)
88 : : : m_xFactory(xFactory)
89 [ + - ][ + - ]: 191 : , m_xEntityResolver(new CDefaultEntityResolver())
[ + - ][ + - ]
90 : : {
91 : : // init libxml. libxml will protect itself against multiple
92 : : // initializations so there is no problem here if this gets
93 : : // called multiple times.
94 [ + - ]: 191 : xmlInitParser();
95 : 191 : }
96 : :
97 : 191 : Reference< XInterface > CDocumentBuilder::_getInstance(const Reference< XMultiServiceFactory >& rSMgr)
98 : : {
99 [ + - ][ + - ]: 191 : return static_cast< XDocumentBuilder* >(new CDocumentBuilder(rSMgr));
100 : : }
101 : :
102 : : const char* CDocumentBuilder::aImplementationName = "com.sun.star.comp.xml.dom.DocumentBuilder";
103 : : const char* CDocumentBuilder::aSupportedServiceNames[] = {
104 : : "com.sun.star.xml.dom.DocumentBuilder",
105 : : NULL
106 : : };
107 : :
108 : 638 : OUString CDocumentBuilder::_getImplementationName()
109 : : {
110 : 638 : return OUString::createFromAscii(aImplementationName);
111 : : }
112 : 191 : Sequence<OUString> CDocumentBuilder::_getSupportedServiceNames()
113 : : {
114 : 191 : Sequence<OUString> aSequence;
115 [ + + ]: 382 : for (int i=0; aSupportedServiceNames[i]!=NULL; i++) {
116 [ + - ]: 191 : aSequence.realloc(i+1);
117 [ + - ]: 191 : aSequence[i]=(OUString::createFromAscii(aSupportedServiceNames[i]));
118 : : }
119 : 191 : return aSequence;
120 : : }
121 : :
122 : 0 : Sequence< OUString > SAL_CALL CDocumentBuilder::getSupportedServiceNames()
123 : : throw (RuntimeException)
124 : : {
125 : 0 : return CDocumentBuilder::_getSupportedServiceNames();
126 : : }
127 : :
128 : 0 : OUString SAL_CALL CDocumentBuilder::getImplementationName()
129 : : throw (RuntimeException)
130 : : {
131 : 0 : return CDocumentBuilder::_getImplementationName();
132 : : }
133 : :
134 : 0 : sal_Bool SAL_CALL CDocumentBuilder::supportsService(const OUString& aServiceName)
135 : : throw (RuntimeException)
136 : : {
137 [ # # ]: 0 : Sequence< OUString > supported = CDocumentBuilder::_getSupportedServiceNames();
138 [ # # ]: 0 : for (sal_Int32 i=0; i<supported.getLength(); i++)
139 : : {
140 [ # # ][ # # ]: 0 : if (supported[i] == aServiceName) return sal_True;
141 : : }
142 [ # # ]: 0 : return sal_False;
143 : : }
144 : :
145 : 2 : Reference< XDOMImplementation > SAL_CALL CDocumentBuilder::getDOMImplementation()
146 : : throw (RuntimeException)
147 : : {
148 : :
149 : 2 : return Reference< XDOMImplementation >();
150 : : }
151 : :
152 : 8186 : sal_Bool SAL_CALL CDocumentBuilder::isNamespaceAware()
153 : : throw (RuntimeException)
154 : : {
155 : 8186 : return sal_True;
156 : : }
157 : :
158 : 2 : sal_Bool SAL_CALL CDocumentBuilder::isValidating()
159 : : throw (RuntimeException)
160 : : {
161 : 2 : return sal_False;
162 : : }
163 : :
164 : 3652 : Reference< XDocument > SAL_CALL CDocumentBuilder::newDocument()
165 : : throw (RuntimeException)
166 : : {
167 [ + - ]: 3652 : ::osl::MutexGuard const g(m_Mutex);
168 : :
169 : : // create a new document
170 [ + - ]: 3652 : xmlDocPtr pDocument = xmlNewDoc((const xmlChar*)"1.0");
171 : : Reference< XDocument > const xRet(
172 [ + - ][ + - ]: 3652 : CDocument::CreateCDocument(pDocument).get());
[ + - ]
173 [ + - ]: 3652 : return xRet;
174 : : }
175 : :
176 : 4 : static OUString make_error_message(xmlParserCtxtPtr ctxt)
177 : : {
178 : 4 : OUStringBuffer buf;
179 [ + - ]: 4 : buf.appendAscii(ctxt->lastError.message);
180 [ + - ]: 4 : buf.appendAscii("Line: ");
181 [ + - ]: 4 : buf.append(static_cast<sal_Int32>(ctxt->lastError.line));
182 [ + - ]: 4 : buf.appendAscii("\nColumn: ");
183 [ + - ]: 4 : buf.append(static_cast<sal_Int32>(ctxt->lastError.int2));
184 [ + - ]: 4 : OUString msg = buf.makeStringAndClear();
185 : 4 : return msg;
186 : : }
187 : :
188 : : // -- callbacks and context struct for parsing from stream
189 : : // -- c-linkage, so the callbacks can be used by libxml
190 : : extern "C" {
191 : :
192 : : // context struct passed to IO functions
193 : 17422 : typedef struct context {
194 : : CDocumentBuilder *pBuilder;
195 : : Reference< XInputStream > rInputStream;
196 : : bool close;
197 : : bool freeOnClose;
198 : : } context_t;
199 : :
200 : 17564 : static int xmlIO_read_func( void *context, char *buffer, int len)
201 : : {
202 : : // get the context...
203 : 17564 : context_t *pctx = static_cast<context_t*>(context);
204 [ - + ]: 17564 : if (!pctx->rInputStream.is())
205 : 0 : return -1;
206 : : try {
207 : : // try to read the requested number of bytes
208 [ + - ]: 17564 : Sequence< sal_Int8 > chunk(len);
209 [ + - ][ + - ]: 17564 : int nread = pctx->rInputStream->readBytes(chunk, len);
210 : :
211 : : // copy bytes to the provided buffer
212 [ + - ]: 17564 : rtl_copyMemory(buffer, chunk.getConstArray(), nread);
213 [ + - ][ # # ]: 17564 : return nread;
214 : 0 : } catch (const com::sun::star::uno::Exception& ex) {
215 : : (void) ex;
216 : : OSL_FAIL(OUStringToOString(ex.Message, RTL_TEXTENCODING_UTF8).getStr());
217 : 0 : return -1;
218 : : }
219 : : }
220 : :
221 : 8711 : static int xmlIO_close_func(void* context)
222 : : {
223 : : // get the context...
224 : 8711 : context_t *pctx = static_cast<context_t*>(context);
225 [ - + ]: 8711 : if (!pctx->rInputStream.is())
226 : 0 : return 0;
227 : : try
228 : : {
229 [ - + ]: 8711 : if (pctx->close)
230 [ # # ][ # # ]: 0 : pctx->rInputStream->closeInput();
231 [ - + ]: 8711 : if (pctx->freeOnClose)
232 [ # # ][ # # ]: 0 : delete pctx;
233 [ # # ]: 8711 : return 0;
234 : 0 : } catch (const com::sun::star::uno::Exception& ex) {
235 : : (void) ex;
236 : : OSL_FAIL(OUStringToOString(ex.Message, RTL_TEXTENCODING_UTF8).getStr());
237 : 0 : return -1;
238 : : }
239 : : }
240 : :
241 : 0 : static xmlParserInputPtr resolve_func(void *ctx,
242 : : const xmlChar *publicId,
243 : : const xmlChar *systemId)
244 : : {
245 : : // get the CDocumentBuilder object
246 : 0 : xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
247 : 0 : CDocumentBuilder *builder = static_cast< CDocumentBuilder* >(ctxt->_private);
248 [ # # ]: 0 : Reference< XEntityResolver > resolver = builder->getEntityResolver();
249 : 0 : OUString sysid;
250 [ # # ]: 0 : if (systemId != 0)
251 [ # # ]: 0 : sysid = OUString((sal_Char*)systemId, strlen((char*)systemId), RTL_TEXTENCODING_UTF8);
252 : 0 : OUString pubid;
253 [ # # ]: 0 : if (publicId != 0)
254 [ # # ]: 0 : pubid = OUString((sal_Char*)publicId, strlen((char*)publicId), RTL_TEXTENCODING_UTF8);
255 : :
256 : : // resolve the entity
257 [ # # ][ # # ]: 0 : InputSource src = resolver->resolveEntity(pubid, sysid);
258 : :
259 : : // create IO context on heap because this call will no longer be on the stack
260 : : // when IO is actually performed through the callbacks. The close function must
261 : : // free the memory which is indicated by the freeOnClose field in the context struct
262 [ # # ][ # # ]: 0 : context_t *c = new context_t;
263 : 0 : c->pBuilder = builder;
264 [ # # ]: 0 : c->rInputStream = src.aInputStream;
265 : 0 : c->close = true;
266 : 0 : c->freeOnClose = true;
267 : :
268 : : // set up the inputBuffer and inputPtr for libxml
269 : : xmlParserInputBufferPtr pBuffer =
270 [ # # ]: 0 : xmlParserInputBufferCreateIO(xmlIO_read_func, xmlIO_close_func, c, XML_CHAR_ENCODING_NONE);
271 : : xmlParserInputPtr pInput =
272 [ # # ]: 0 : xmlNewIOInputStream(ctxt, pBuffer, XML_CHAR_ENCODING_NONE);
273 [ # # ]: 0 : return pInput;
274 : : }
275 : :
276 : : #if 0
277 : : static xmlParserInputPtr external_entity_loader(const char *URL, const char * /*ID*/, xmlParserCtxtPtr ctxt)
278 : : {
279 : : // just call our resolver function using the URL as systemId
280 : : return resolve_func(ctxt, 0, (const xmlChar*)URL);
281 : : }
282 : : #endif
283 : :
284 : : // default warning handler does not trigger assertion
285 : 2 : static void warning_func(void * ctx, const char * /*msg*/, ...)
286 : : {
287 : 2 : OUStringBuffer buf("libxml2 warning\n");
288 [ + - ][ + - ]: 2 : buf.append(make_error_message(static_cast< xmlParserCtxtPtr >(ctx)));
289 [ + - ][ + - ]: 2 : OString msg = OUStringToOString(buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US);
290 : 2 : OSL_TRACE(msg.getStr());
291 : 2 : }
292 : :
293 : : // default error handler triggers assertion
294 : 0 : static void error_func(void * ctx, const char * /*msg*/, ...)
295 : : {
296 : 0 : OUStringBuffer buf("libxml2 error\n");
297 [ # # ][ # # ]: 0 : buf.append(make_error_message(static_cast< xmlParserCtxtPtr >(ctx)));
298 [ # # ][ # # ]: 0 : OString msg = OUStringToOString(buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US);
299 : 0 : OSL_FAIL(msg.getStr());
300 : 0 : }
301 : :
302 : : } // extern "C"
303 : :
304 : 2 : void throwEx(xmlParserCtxtPtr ctxt)
305 : : {
306 [ + - ]: 2 : com::sun::star::xml::sax::SAXParseException saxex;
307 [ + - ]: 2 : saxex.Message = make_error_message(ctxt);
308 : 2 : saxex.LineNumber = static_cast<sal_Int32>(ctxt->lastError.line);
309 : 2 : saxex.ColumnNumber = static_cast<sal_Int32>(ctxt->lastError.int2);
310 [ + - ]: 2 : throw saxex;
311 : : }
312 : :
313 : 8713 : Reference< XDocument > SAL_CALL CDocumentBuilder::parse(const Reference< XInputStream >& is)
314 : : throw (RuntimeException, SAXParseException, IOException)
315 : : {
316 [ + + ]: 8713 : if (!is.is()) {
317 [ + - ]: 2 : throw RuntimeException();
318 : : }
319 : :
320 [ + - ]: 8711 : ::osl::MutexGuard const g(m_Mutex);
321 : :
322 : : // encoding...
323 : : /*
324 : : xmlChar *encstr = (xmlChar*) OUStringToOString(src.sEncoding, RTL_TEXTENCODING_UTF8).getStr();
325 : : xmlCharEncoding enc = xmlParseCharEncoding(encstr);
326 : : */
327 : :
328 : : ::boost::shared_ptr<xmlParserCtxt> const pContext(
329 [ + - ][ + - ]: 8711 : xmlNewParserCtxt(), xmlFreeParserCtxt);
330 : :
331 : : // register error functions to prevent errors being printed
332 : : // on the console
333 : 8711 : pContext->_private = this;
334 : 8711 : pContext->sax->error = error_func;
335 : 8711 : pContext->sax->warning = warning_func;
336 : 8711 : pContext->sax->resolveEntity = resolve_func;
337 : :
338 : : // IO context struct
339 [ + - ]: 8711 : context_t c;
340 : 8711 : c.pBuilder = this;
341 [ + - ]: 8711 : c.rInputStream = is;
342 : : // we did not open the stream, thus we do not close it.
343 : 8711 : c.close = false;
344 : 8711 : c.freeOnClose = false;
345 : : xmlDocPtr const pDoc = xmlCtxtReadIO(pContext.get(),
346 [ + - ]: 8711 : xmlIO_read_func, xmlIO_close_func, &c, 0, 0, 0);
347 : :
348 [ - + ]: 8711 : if (pDoc == 0) {
349 [ # # ]: 0 : throwEx(pContext.get());
350 : : }
351 : : Reference< XDocument > const xRet(
352 [ + - ][ + - ]: 8711 : CDocument::CreateCDocument(pDoc).get());
[ + - ]
353 [ + - ][ + - ]: 8713 : return xRet;
[ + - ]
354 : : }
355 : :
356 : 4 : Reference< XDocument > SAL_CALL CDocumentBuilder::parseURI(const OUString& sUri)
357 : : throw (RuntimeException, SAXParseException, IOException)
358 : : {
359 [ + - ]: 4 : ::osl::MutexGuard const g(m_Mutex);
360 : :
361 : : ::boost::shared_ptr<xmlParserCtxt> const pContext(
362 [ + - ][ + - ]: 4 : xmlNewParserCtxt(), xmlFreeParserCtxt);
363 : 4 : pContext->_private = this;
364 : 4 : pContext->sax->error = error_func;
365 : 4 : pContext->sax->warning = warning_func;
366 : 4 : pContext->sax->resolveEntity = resolve_func;
367 : : // xmlSetExternalEntityLoader(external_entity_loader);
368 [ + - ]: 4 : OString oUri = OUStringToOString(sUri, RTL_TEXTENCODING_UTF8);
369 : 4 : char *uri = (char*) oUri.getStr();
370 [ + - ]: 4 : xmlDocPtr pDoc = xmlCtxtReadFile(pContext.get(), uri, 0, 0);
371 [ + + ]: 4 : if (pDoc == 0) {
372 [ - + ]: 2 : throwEx(pContext.get());
373 : : }
374 : : Reference< XDocument > const xRet(
375 [ + - ][ + - ]: 2 : CDocument::CreateCDocument(pDoc).get());
[ + - ]
376 [ + - ][ + - ]: 4 : return xRet;
377 : : }
378 : :
379 : : void SAL_CALL
380 : 2 : CDocumentBuilder::setEntityResolver(Reference< XEntityResolver > const& xER)
381 : : throw (RuntimeException)
382 : : {
383 [ + - ]: 2 : ::osl::MutexGuard const g(m_Mutex);
384 : :
385 [ + - ][ + - ]: 2 : m_xEntityResolver = xER;
386 : 2 : }
387 : :
388 : 0 : Reference< XEntityResolver > SAL_CALL CDocumentBuilder::getEntityResolver()
389 : : throw (RuntimeException)
390 : : {
391 [ # # ]: 0 : ::osl::MutexGuard const g(m_Mutex);
392 : :
393 [ # # ]: 0 : return m_xEntityResolver;
394 : : }
395 : :
396 : : void SAL_CALL
397 : 2 : CDocumentBuilder::setErrorHandler(Reference< XErrorHandler > const& xEH)
398 : : throw (RuntimeException)
399 : : {
400 [ + - ]: 2 : ::osl::MutexGuard const g(m_Mutex);
401 : :
402 [ + - ][ + - ]: 2 : m_xErrorHandler = xEH;
403 : 2 : }
404 : : }
405 : :
406 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|