...as reported during CppunitTest_extensions_test_update (see below). I don't see a reason why those pContext should be shared_ptr, so better make them unique_ptr to guarantee that xmlFreeParserCtxt is called with c still in scope (in CDocumentBuilder::parse). > ==10883==ERROR: AddressSanitizer: stack-use-after-scope on address 0x2b111da94b68 at pc 0x2b116e55a200 bp 0x7fff7228b0f0 sp 0x7fff7228b0e8 > READ of size 8 at 0x2b111da94b68 thread T0 > #0 0x2b116e55a1ff in com::sun:⭐:uno::BaseReference::is() const include/com/sun/star/uno/Reference.h:94:27 > #1 0x2b116e699756 in DOM::xmlIO_close_func(void*) unoxml/source/dom/documentbuilder.cxx:214:33 > #2 0x2b11300cf646 in xmlFreeParserInputBuffer__internal_alias workdir/UnpackedTarball/xml2/xmlIO.c:2575:2 > #3 0x2b112fdd2706 in xmlFreeInputStream__internal_alias workdir/UnpackedTarball/xml2/parserInternals.c:1341:9 > #4 0x2b112fddebf3 in xmlFreeParserCtxt__internal_alias workdir/UnpackedTarball/xml2/parserInternals.c:1774:9 > #5 0x2b116e6aaddc in std::_Sp_counted_deleter<_xmlParserCtxt*, void (*)(_xmlParserCtxt*), std::allocator<void>, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/lib/gcc/x86_64-redhat-linux/6.3.1/../../../../include/c++/6.3.1/bits/shared_ptr_base.h:464:9 > #6 0x2b116e65370a in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/lib/gcc/x86_64-redhat-linux/6.3.1/../../../../include/c++/6.3.1/bits/shared_ptr_base.h:150:6 > #7 0x2b116e653494 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/lib/gcc/x86_64-redhat-linux/6.3.1/../../../../include/c++/6.3.1/bits/shared_ptr_base.h:662:11 > #8 0x2b116e6a78b1 in std::__shared_ptr<_xmlParserCtxt, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/lib/gcc/x86_64-redhat-linux/6.3.1/../../../../include/c++/6.3.1/bits/shared_ptr_base.h:928:31 > #9 0x2b116e69f01d in std::shared_ptr<_xmlParserCtxt>::~shared_ptr() /usr/lib/gcc/x86_64-redhat-linux/6.3.1/../../../../include/c++/6.3.1/bits/shared_ptr.h:93:11 > #10 0x2b116e696aca in DOM::CDocumentBuilder::parse(com::sun:⭐:uno::Reference<com::sun:⭐:io::XInputStream> const&) unoxml/source/dom/documentbuilder.cxx:336:5 > #11 0x2b116e699fe2 in non-virtual thunk to DOM::CDocumentBuilder::parse(com::sun:⭐:uno::Reference<com::sun:⭐:io::XInputStream> const&) unoxml/source/dom/documentbuilder.cxx > #12 0x2b116df6449a in (anonymous namespace)::UpdateInformationProvider::getUpdateInformationEnumeration(com::sun:⭐:uno::Sequence<rtl::OUString> const&, rtl::OUString const&) extensions/source/update/feed/updatefeed.cxx:589:83 > #13 0x2b116df682ea in non-virtual thunk to (anonymous namespace)::UpdateInformationProvider::getUpdateInformationEnumeration(com::sun:⭐:uno::Sequence<rtl::OUString> const&, rtl::OUString const&) extensions/source/update/feed/updatefeed.cxx > #14 0x2b115d9a73eb in testupdate::Test::testGetUpdateInformationEnumeration() extensions/qa/update/test_update.cxx:57:26 > #15 0x2b115d9baf1b in CppUnit::TestCaller<testupdate::Test>::runTest() workdir/UnpackedTarball/cppunit/include/cppunit/TestCaller.h:166:6 > #16 0x2b111904ad8b in CppUnit::TestCaseMethodFunctor::operator()() const workdir/UnpackedTarball/cppunit/src/cppunit/TestCase.cpp:32:5 > #17 0x2b11322dab0f in (anonymous namespace)::Protector::protect(CppUnit::Functor const&, CppUnit::ProtectorContext const&) test/source/vclbootstrapprotector.cxx:39:14 > #18 0x2b11190093ce in CppUnit::ProtectorChain::ProtectFunctor::operator()() const workdir/UnpackedTarball/cppunit/src/cppunit/ProtectorChain.cpp:20:25 > #19 0x2b1128c6214f in (anonymous namespace)::Prot::protect(CppUnit::Functor const&, CppUnit::ProtectorContext const&) unotest/source/cpp/unobootstrapprotector/unobootstrapprotector.cxx:89:12 > #20 0x2b11190093ce in CppUnit::ProtectorChain::ProtectFunctor::operator()() const workdir/UnpackedTarball/cppunit/src/cppunit/ProtectorChain.cpp:20:25 > #21 0x2b1124efc351 in (anonymous namespace)::Prot::protect(CppUnit::Functor const&, CppUnit::ProtectorContext const&) unotest/source/cpp/unoexceptionprotector/unoexceptionprotector.cxx:63:16 > #22 0x2b11190093ce in CppUnit::ProtectorChain::ProtectFunctor::operator()() const workdir/UnpackedTarball/cppunit/src/cppunit/ProtectorChain.cpp:20:25 > #23 0x2b1118f87350 in CppUnit::DefaultProtector::protect(CppUnit::Functor const&, CppUnit::ProtectorContext const&) workdir/UnpackedTarball/cppunit/src/cppunit/DefaultProtector.cpp:15:12 > #24 0x2b11190093ce in CppUnit::ProtectorChain::ProtectFunctor::operator()() const workdir/UnpackedTarball/cppunit/src/cppunit/ProtectorChain.cpp:20:25 > #25 0x2b1119005e70 in CppUnit::ProtectorChain::protect(CppUnit::Functor const&, CppUnit::ProtectorContext const&) workdir/UnpackedTarball/cppunit/src/cppunit/ProtectorChain.cpp:77:18 > #26 0x2b11190c50f5 in CppUnit::TestResult::protect(CppUnit::Functor const&, CppUnit::Test*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) workdir/UnpackedTarball/cppunit/src/cppunit/TestResult.cpp:181:28 > #27 0x2b1119048fa4 in CppUnit::TestCase::run(CppUnit::TestResult*) workdir/UnpackedTarball/cppunit/src/cppunit/TestCase.cpp:91:13 > #28 0x2b111904d7a7 in CppUnit::TestComposite::doRunChildTests(CppUnit::TestResult*) workdir/UnpackedTarball/cppunit/src/cppunit/TestComposite.cpp:64:30 > #29 0x2b111904c819 in CppUnit::TestComposite::run(CppUnit::TestResult*) workdir/UnpackedTarball/cppunit/src/cppunit/TestComposite.cpp:23:3 > #30 0x2b111904d7a7 in CppUnit::TestComposite::doRunChildTests(CppUnit::TestResult*) workdir/UnpackedTarball/cppunit/src/cppunit/TestComposite.cpp:64:30 > #31 0x2b111904c819 in CppUnit::TestComposite::run(CppUnit::TestResult*) workdir/UnpackedTarball/cppunit/src/cppunit/TestComposite.cpp:23:3 > #32 0x2b11191035c9 in CppUnit::TestRunner::WrappingSuite::run(CppUnit::TestResult*) workdir/UnpackedTarball/cppunit/src/cppunit/TestRunner.cpp:47:27 > #33 0x2b11190c340d in CppUnit::TestResult::runTest(CppUnit::Test*) workdir/UnpackedTarball/cppunit/src/cppunit/TestResult.cpp:148:9 > #34 0x2b111910489b in CppUnit::TestRunner::run(CppUnit::TestResult&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) workdir/UnpackedTarball/cppunit/src/cppunit/TestRunner.cpp:96:14 > #35 0x532fb4 in (anonymous namespace)::ProtectedFixtureFunctor::run() const sal/cppunittester/cppunittester.cxx:306:20 > #36 0x52e7c3 in sal_main() sal/cppunittester/cppunittester.cxx:456:20 > #37 0x52cb6f in main sal/cppunittester/cppunittester.cxx:363:1 > #38 0x2b111acb5400 in __libc_start_main (/lib64/libc.so.6+0x20400) > #39 0x438019 in _start (workdir/LinkTarget/Executable/cppunittester+0x438019) > > Address 0x2b111da94b68 is located in stack of thread T0 at offset 104 in frame > #0 0x2b116e69553f in DOM::CDocumentBuilder::parse(com::sun:⭐:uno::Reference<com::sun:⭐:io::XInputStream> const&) unoxml/source/dom/documentbuilder.cxx:303 > > This frame has 4 object(s): > [32, 40) 'g' (line 308) > [64, 80) 'pContext' (line 310) > [96, 120) 'c' (line 321) <== Memory access at offset 104 is inside this variable > [160, 168) 'ref.tmp' (line 333) Change-Id: I3398d54776af4927417e392e55bbca740d4121af
395 lines
13 KiB
C++
395 lines
13 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <documentbuilder.hxx>
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
|
|
#include <libxml/xmlerror.h>
|
|
#include <libxml/tree.h>
|
|
|
|
#include <memory>
|
|
|
|
#include <rtl/alloc.h>
|
|
#include <rtl/ustrbuf.hxx>
|
|
#include <osl/diagnose.h>
|
|
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <cppuhelper/implbase.hxx>
|
|
#include <cppuhelper/supportsservice.hxx>
|
|
|
|
#include <com/sun/star/xml/sax/SAXParseException.hpp>
|
|
#include <com/sun/star/ucb/XCommandEnvironment.hpp>
|
|
#include <com/sun/star/task/XInteractionHandler.hpp>
|
|
|
|
#include <ucbhelper/content.hxx>
|
|
#include <ucbhelper/commandenvironment.hxx>
|
|
|
|
#include <node.hxx>
|
|
#include <document.hxx>
|
|
|
|
using namespace css::io;
|
|
using namespace css::lang;
|
|
using namespace css::ucb;
|
|
using namespace css::uno;
|
|
using namespace css::xml::dom;
|
|
using namespace css::xml::sax;
|
|
using namespace ucbhelper;
|
|
using css::task::XInteractionHandler;
|
|
using css::xml::sax::InputSource;
|
|
|
|
|
|
namespace DOM
|
|
{
|
|
|
|
class CDefaultEntityResolver : public cppu::WeakImplHelper< XEntityResolver >
|
|
{
|
|
public:
|
|
virtual InputSource SAL_CALL resolveEntity( const OUString& sPublicId, const OUString& sSystemId ) override
|
|
{
|
|
InputSource is;
|
|
is.sPublicId = sPublicId;
|
|
is.sSystemId = sSystemId;
|
|
is.sEncoding.clear();
|
|
|
|
try {
|
|
Reference< XCommandEnvironment > aEnvironment(
|
|
new CommandEnvironment(Reference< XInteractionHandler >(),
|
|
Reference< XProgressHandler >() ));
|
|
Content aContent(sSystemId, aEnvironment, comphelper::getProcessComponentContext());
|
|
|
|
is.aInputStream = aContent.openStream();
|
|
} catch (const css::uno::Exception&) {
|
|
OSL_FAIL("exception in default entity resolver");
|
|
is.aInputStream.clear();
|
|
}
|
|
return is;
|
|
}
|
|
|
|
};
|
|
|
|
CDocumentBuilder::CDocumentBuilder()
|
|
: m_xEntityResolver(new CDefaultEntityResolver)
|
|
{
|
|
// init libxml. libxml will protect itself against multiple
|
|
// initializations so there is no problem here if this gets
|
|
// called multiple times.
|
|
xmlInitParser();
|
|
}
|
|
|
|
Reference< XInterface > CDocumentBuilder::_getInstance(const Reference< XMultiServiceFactory >& )
|
|
{
|
|
return static_cast< XDocumentBuilder* >(new CDocumentBuilder);
|
|
}
|
|
|
|
const char* CDocumentBuilder::aImplementationName = "com.sun.star.comp.xml.dom.DocumentBuilder";
|
|
const char* CDocumentBuilder::aSupportedServiceNames[] = {
|
|
"com.sun.star.xml.dom.DocumentBuilder",
|
|
nullptr
|
|
};
|
|
|
|
OUString CDocumentBuilder::_getImplementationName()
|
|
{
|
|
return OUString::createFromAscii(aImplementationName);
|
|
}
|
|
Sequence<OUString> CDocumentBuilder::_getSupportedServiceNames()
|
|
{
|
|
Sequence<OUString> aSequence;
|
|
for (int i=0; aSupportedServiceNames[i]!=nullptr; i++) {
|
|
aSequence.realloc(i+1);
|
|
aSequence[i]=(OUString::createFromAscii(aSupportedServiceNames[i]));
|
|
}
|
|
return aSequence;
|
|
}
|
|
|
|
Sequence< OUString > SAL_CALL CDocumentBuilder::getSupportedServiceNames()
|
|
{
|
|
return CDocumentBuilder::_getSupportedServiceNames();
|
|
}
|
|
|
|
OUString SAL_CALL CDocumentBuilder::getImplementationName()
|
|
{
|
|
return CDocumentBuilder::_getImplementationName();
|
|
}
|
|
|
|
sal_Bool SAL_CALL CDocumentBuilder::supportsService(const OUString& aServiceName)
|
|
{
|
|
return cppu::supportsService(this, aServiceName);
|
|
}
|
|
|
|
Reference< XDOMImplementation > SAL_CALL CDocumentBuilder::getDOMImplementation()
|
|
{
|
|
|
|
return Reference< XDOMImplementation >();
|
|
}
|
|
|
|
sal_Bool SAL_CALL CDocumentBuilder::isNamespaceAware()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
sal_Bool SAL_CALL CDocumentBuilder::isValidating()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Reference< XDocument > SAL_CALL CDocumentBuilder::newDocument()
|
|
{
|
|
::osl::MutexGuard const g(m_Mutex);
|
|
|
|
// create a new document
|
|
xmlDocPtr pDocument = xmlNewDoc(reinterpret_cast<const xmlChar*>("1.0"));
|
|
Reference< XDocument > const xRet(
|
|
CDocument::CreateCDocument(pDocument).get());
|
|
return xRet;
|
|
}
|
|
|
|
static OUString make_error_message(xmlParserCtxtPtr ctxt)
|
|
{
|
|
OUStringBuffer buf;
|
|
buf.appendAscii(ctxt->lastError.message);
|
|
buf.append("Line: ");
|
|
buf.append(static_cast<sal_Int32>(ctxt->lastError.line));
|
|
buf.append("\nColumn: ");
|
|
buf.append(static_cast<sal_Int32>(ctxt->lastError.int2));
|
|
OUString msg = buf.makeStringAndClear();
|
|
return msg;
|
|
}
|
|
|
|
// -- callbacks and context struct for parsing from stream
|
|
// -- c-linkage, so the callbacks can be used by libxml
|
|
extern "C" {
|
|
|
|
// context struct passed to IO functions
|
|
typedef struct context {
|
|
CDocumentBuilder *pBuilder;
|
|
Reference< XInputStream > rInputStream;
|
|
bool close;
|
|
bool freeOnClose;
|
|
} context_t;
|
|
|
|
static int xmlIO_read_func( void *context, char *buffer, int len)
|
|
{
|
|
// get the context...
|
|
context_t *pctx = static_cast<context_t*>(context);
|
|
if (!pctx->rInputStream.is())
|
|
return -1;
|
|
try {
|
|
// try to read the requested number of bytes
|
|
Sequence< sal_Int8 > chunk(len);
|
|
int nread = pctx->rInputStream->readBytes(chunk, len);
|
|
|
|
// copy bytes to the provided buffer
|
|
memcpy(buffer, chunk.getConstArray(), nread);
|
|
return nread;
|
|
} catch (const css::uno::Exception& ex) {
|
|
(void) ex;
|
|
OSL_FAIL(OUStringToOString(ex.Message, RTL_TEXTENCODING_UTF8).getStr());
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static int xmlIO_close_func(void* context)
|
|
{
|
|
// get the context...
|
|
context_t *pctx = static_cast<context_t*>(context);
|
|
if (!pctx->rInputStream.is())
|
|
return 0;
|
|
try
|
|
{
|
|
if (pctx->close)
|
|
pctx->rInputStream->closeInput();
|
|
if (pctx->freeOnClose)
|
|
delete pctx;
|
|
return 0;
|
|
} catch (const css::uno::Exception& ex) {
|
|
(void) ex;
|
|
OSL_FAIL(OUStringToOString(ex.Message, RTL_TEXTENCODING_UTF8).getStr());
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static xmlParserInputPtr resolve_func(void *ctx,
|
|
const xmlChar *publicId,
|
|
const xmlChar *systemId)
|
|
{
|
|
// get the CDocumentBuilder object
|
|
xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(ctx);
|
|
CDocumentBuilder *builder = static_cast< CDocumentBuilder* >(ctxt->_private);
|
|
Reference< XEntityResolver > resolver = builder->getEntityResolver();
|
|
OUString sysid;
|
|
if (systemId != nullptr)
|
|
sysid = OUString(reinterpret_cast<char const *>(systemId), strlen(reinterpret_cast<char const *>(systemId)), RTL_TEXTENCODING_UTF8);
|
|
OUString pubid;
|
|
if (publicId != nullptr)
|
|
pubid = OUString(reinterpret_cast<char const *>(publicId), strlen(reinterpret_cast<char const *>(publicId)), RTL_TEXTENCODING_UTF8);
|
|
|
|
// resolve the entity
|
|
InputSource src = resolver->resolveEntity(pubid, sysid);
|
|
|
|
// create IO context on heap because this call will no longer be on the stack
|
|
// when IO is actually performed through the callbacks. The close function must
|
|
// free the memory which is indicated by the freeOnClose field in the context struct
|
|
context_t *c = new context_t;
|
|
c->pBuilder = builder;
|
|
c->rInputStream = src.aInputStream;
|
|
c->close = true;
|
|
c->freeOnClose = true;
|
|
|
|
// set up the inputBuffer and inputPtr for libxml
|
|
xmlParserInputBufferPtr pBuffer =
|
|
xmlParserInputBufferCreateIO(xmlIO_read_func, xmlIO_close_func, c, XML_CHAR_ENCODING_NONE);
|
|
xmlParserInputPtr pInput =
|
|
xmlNewIOInputStream(ctxt, pBuffer, XML_CHAR_ENCODING_NONE);
|
|
return pInput;
|
|
}
|
|
|
|
#if 0
|
|
static xmlParserInputPtr external_entity_loader(const char *URL, const char * /*ID*/, xmlParserCtxtPtr ctxt)
|
|
{
|
|
// just call our resolver function using the URL as systemId
|
|
return resolve_func(ctxt, 0, (const xmlChar*)URL);
|
|
}
|
|
#endif
|
|
|
|
// default warning handler does not trigger assertion
|
|
static void warning_func(void * ctx, const char * /*msg*/, ...)
|
|
{
|
|
SAL_INFO(
|
|
"unoxml",
|
|
"libxml2 warning: "
|
|
<< make_error_message(static_cast<xmlParserCtxtPtr>(ctx)));
|
|
}
|
|
|
|
// default error handler triggers assertion
|
|
static void error_func(void * ctx, const char * /*msg*/, ...)
|
|
{
|
|
SAL_WARN(
|
|
"unoxml",
|
|
"libxml2 error: "
|
|
<< make_error_message(static_cast<xmlParserCtxtPtr>(ctx)));
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
void throwEx(xmlParserCtxtPtr ctxt)
|
|
{
|
|
css::xml::sax::SAXParseException saxex;
|
|
saxex.Message = make_error_message(ctxt);
|
|
saxex.LineNumber = static_cast<sal_Int32>(ctxt->lastError.line);
|
|
saxex.ColumnNumber = static_cast<sal_Int32>(ctxt->lastError.int2);
|
|
throw saxex;
|
|
}
|
|
|
|
namespace {
|
|
|
|
struct XmlFreeParserCtxt {
|
|
void operator ()(xmlParserCtxt * p) const { xmlFreeParserCtxt(p); }
|
|
};
|
|
|
|
}
|
|
|
|
Reference< XDocument > SAL_CALL CDocumentBuilder::parse(const Reference< XInputStream >& is)
|
|
{
|
|
if (!is.is()) {
|
|
throw RuntimeException();
|
|
}
|
|
|
|
::osl::MutexGuard const g(m_Mutex);
|
|
|
|
// IO context struct. Must outlive pContext, as destroying that via
|
|
// xmlFreeParserCtxt may still access this context_t
|
|
context_t c;
|
|
c.pBuilder = this;
|
|
c.rInputStream = is;
|
|
// we did not open the stream, thus we do not close it.
|
|
c.close = false;
|
|
c.freeOnClose = false;
|
|
|
|
std::unique_ptr<xmlParserCtxt, XmlFreeParserCtxt> const pContext(
|
|
xmlNewParserCtxt());
|
|
|
|
// register error functions to prevent errors being printed
|
|
// on the console
|
|
pContext->_private = this;
|
|
pContext->sax->error = error_func;
|
|
pContext->sax->warning = warning_func;
|
|
pContext->sax->resolveEntity = resolve_func;
|
|
|
|
xmlDocPtr const pDoc = xmlCtxtReadIO(pContext.get(),
|
|
xmlIO_read_func, xmlIO_close_func, &c, nullptr, nullptr, 0);
|
|
|
|
if (pDoc == nullptr) {
|
|
throwEx(pContext.get());
|
|
}
|
|
Reference< XDocument > const xRet(
|
|
CDocument::CreateCDocument(pDoc).get());
|
|
return xRet;
|
|
}
|
|
|
|
Reference< XDocument > SAL_CALL CDocumentBuilder::parseURI(const OUString& sUri)
|
|
{
|
|
::osl::MutexGuard const g(m_Mutex);
|
|
|
|
std::unique_ptr<xmlParserCtxt, XmlFreeParserCtxt> const pContext(
|
|
xmlNewParserCtxt());
|
|
pContext->_private = this;
|
|
pContext->sax->error = error_func;
|
|
pContext->sax->warning = warning_func;
|
|
pContext->sax->resolveEntity = resolve_func;
|
|
// xmlSetExternalEntityLoader(external_entity_loader);
|
|
OString oUri = OUStringToOString(sUri, RTL_TEXTENCODING_UTF8);
|
|
char *uri = const_cast<char*>(oUri.getStr());
|
|
xmlDocPtr pDoc = xmlCtxtReadFile(pContext.get(), uri, nullptr, 0);
|
|
if (pDoc == nullptr) {
|
|
throwEx(pContext.get());
|
|
}
|
|
Reference< XDocument > const xRet(
|
|
CDocument::CreateCDocument(pDoc).get());
|
|
return xRet;
|
|
}
|
|
|
|
void SAL_CALL
|
|
CDocumentBuilder::setEntityResolver(Reference< XEntityResolver > const& xER)
|
|
{
|
|
::osl::MutexGuard const g(m_Mutex);
|
|
|
|
m_xEntityResolver = xER;
|
|
}
|
|
|
|
Reference< XEntityResolver > SAL_CALL CDocumentBuilder::getEntityResolver()
|
|
{
|
|
::osl::MutexGuard const g(m_Mutex);
|
|
|
|
return m_xEntityResolver;
|
|
}
|
|
|
|
void SAL_CALL
|
|
CDocumentBuilder::setErrorHandler(Reference< XErrorHandler > const& xEH)
|
|
{
|
|
::osl::MutexGuard const g(m_Mutex);
|
|
|
|
m_xErrorHandler = xEH;
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|