diff options
Diffstat (limited to 'unoxml/source/dom/documentbuilder.cxx')
-rw-r--r-- | unoxml/source/dom/documentbuilder.cxx | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/unoxml/source/dom/documentbuilder.cxx b/unoxml/source/dom/documentbuilder.cxx new file mode 100644 index 000000000000..7f6777620d87 --- /dev/null +++ b/unoxml/source/dom/documentbuilder.cxx @@ -0,0 +1,432 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: documentbuilder.cxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "documentbuilder.hxx" +#include "node.hxx" +#include "document.hxx" + +#include <rtl/alloc.h> +#include <rtl/memory.h> +#include <rtl/ustrbuf.hxx> + +#include <cppuhelper/implbase1.hxx> + +#include <libxml/xmlerror.h> + +#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 <string.h> +#include <stdio.h> +#include <stdarg.h> + + +using ::rtl::OUStringBuffer; +using ::rtl::OString; +using ::com::sun::star::xml::sax::InputSource; +using namespace ucbhelper; +using namespace ::com::sun::star::ucb; +using ::com::sun::star::task::XInteractionHandler; + + +namespace DOM +{ + extern "C" { + //char *strdup(const char *s); + /* + static char* strdupfunc(const char* s) + { + sal_Int32 len = 0; + while (s[len] != '\0') len++; + char *newStr = (char*)rtl_allocateMemory(len+1); + if (newStr != NULL) + rtl_copyMemory(newStr, s, len+1); + return newStr; + } + */ + } + + + class CDefaultEntityResolver : public cppu::WeakImplHelper1< XEntityResolver > + { + public: + virtual InputSource SAL_CALL resolveEntity( const OUString& sPublicId, const OUString& sSystemId ) + throw (::com::sun::star::uno::RuntimeException) + { + InputSource is; + is.sPublicId = sPublicId; + is.sSystemId = sSystemId; + is.sEncoding = OUString(); + + try { + Reference< XCommandEnvironment > aEnvironment( + new CommandEnvironment(Reference< XInteractionHandler >(), + Reference< XProgressHandler >() )); + Content aContent(sSystemId, aEnvironment); + + is.aInputStream = aContent.openStream(); + } catch (com::sun::star::uno::Exception) { + OSL_ENSURE(sal_False, "exception in default entity resolver"); + is.aInputStream = Reference< XInputStream >(); + } + return is; + } + + }; + + CDocumentBuilder::CDocumentBuilder(const Reference< XMultiServiceFactory >& xFactory) + : m_aFactory(xFactory) + , m_aEntityResolver(Reference< 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 >& rSMgr) + { + // XXX + return static_cast< XDocumentBuilder* >(new CDocumentBuilder(rSMgr)); + } + + const char* CDocumentBuilder::aImplementationName = "com.sun.star.comp.xml.dom.DocumentBuilder"; + const char* CDocumentBuilder::aSupportedServiceNames[] = { + "com.sun.star.xml.dom.DocumentBuilder", + NULL + }; + + OUString CDocumentBuilder::_getImplementationName() + { + return OUString::createFromAscii(aImplementationName); + } + Sequence<OUString> CDocumentBuilder::_getSupportedServiceNames() + { + Sequence<OUString> aSequence; + for (int i=0; aSupportedServiceNames[i]!=NULL; i++) { + aSequence.realloc(i+1); + aSequence[i]=(OUString::createFromAscii(aSupportedServiceNames[i])); + } + return aSequence; + } + + Sequence< OUString > SAL_CALL CDocumentBuilder::getSupportedServiceNames() + throw (RuntimeException) + { + return CDocumentBuilder::_getSupportedServiceNames(); + } + + OUString SAL_CALL CDocumentBuilder::getImplementationName() + throw (RuntimeException) + { + return CDocumentBuilder::_getImplementationName(); + } + + sal_Bool SAL_CALL CDocumentBuilder::supportsService(const OUString& aServiceName) + throw (RuntimeException) + { + Sequence< OUString > supported = CDocumentBuilder::_getSupportedServiceNames(); + for (sal_Int32 i=0; i<supported.getLength(); i++) + { + if (supported[i] == aServiceName) return sal_True; + } + return sal_False; + } + + Reference< XDOMImplementation > SAL_CALL CDocumentBuilder::getDOMImplementation() + throw (RuntimeException) + { + + return Reference< XDOMImplementation >(); + } + + sal_Bool SAL_CALL CDocumentBuilder::isNamespaceAware() + throw (RuntimeException) + { + return sal_True; + } + + sal_Bool SAL_CALL CDocumentBuilder::isValidating() + throw (RuntimeException) + { + return sal_False; + } + + Reference< XDocument > SAL_CALL CDocumentBuilder::newDocument() + throw (RuntimeException) + { + // create a new document + xmlDocPtr pDocument = xmlNewDoc((const xmlChar*)"1.0"); + return Reference< XDocument >(static_cast< CDocument* >(CNode::get((xmlNodePtr)pDocument))); + } + + static OUString make_error_message(xmlParserCtxtPtr ctxt) + { + OUStringBuffer buf; + buf.appendAscii(ctxt->lastError.message); + buf.appendAscii("Line: "); + buf.append(static_cast<sal_Int32>(ctxt->lastError.line)); + buf.appendAscii("\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 + rtl_copyMemory(buffer, chunk.getConstArray(), nread); + return nread; + } catch (com::sun::star::uno::Exception& ex) { + (void) ex; + OSL_ENSURE(sal_False, 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 (com::sun::star::uno::Exception& ex) { + (void) ex; + OSL_ENSURE(sal_False, 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 = (xmlParserCtxtPtr)ctx; + CDocumentBuilder *builder = static_cast< CDocumentBuilder* >(ctxt->_private); + Reference< XEntityResolver > resolver = builder->getEntityResolver(); + OUString sysid; + if (systemId != 0) + sysid = OUString((sal_Char*)systemId, strlen((char*)systemId), RTL_TEXTENCODING_UTF8); + OUString pubid; + if (publicId != 0) + pubid = OUString((sal_Char*)publicId, strlen((char*)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; + } + + 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); + } + + // default warning handler triggers assertion + static void warning_func(void * ctx, const char * /*msg*/, ...) + { + OUStringBuffer buf(OUString::createFromAscii("libxml2 warning\n")); + buf.append(make_error_message(static_cast< xmlParserCtxtPtr >(ctx))); + OString msg = OUStringToOString(buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US); + OSL_ENSURE(sal_False, msg.getStr()); + } + + // default error handler triggers assertion + static void error_func(void * ctx, const char * /*msg*/, ...) + { + OUStringBuffer buf(OUString::createFromAscii("libxml2 error\n")); + buf.append(make_error_message(static_cast< xmlParserCtxtPtr >(ctx))); + OString msg = OUStringToOString(buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US); + OSL_ENSURE(sal_False, msg.getStr()); + } + + } // extern "C" + + void throwEx(xmlParserCtxtPtr ctxt) { + OUString msg = make_error_message(ctxt); + xmlFreeParserCtxt(ctxt); + com::sun::star::xml::sax::SAXParseException saxex; + saxex.Message = msg; + saxex.LineNumber = static_cast<sal_Int32>(ctxt->lastError.line); + saxex.ColumnNumber = static_cast<sal_Int32>(ctxt->lastError.int2); + throw saxex; + } + + Reference< XDocument > SAL_CALL CDocumentBuilder::parse(const Reference< XInputStream >& is) + throw (RuntimeException, SAXParseException, IOException) + { + + // encoding... + /* + xmlChar *encstr = (xmlChar*) OUStringToOString(src.sEncoding, RTL_TEXTENCODING_UTF8).getStr(); + xmlCharEncoding enc = xmlParseCharEncoding(encstr); + */ + + xmlParserCtxtPtr ctxt = xmlNewParserCtxt(); + + // register error functions to prevent errors being printed + // on the console + ctxt->_private = this; + ctxt->sax->error = error_func; + ctxt->sax->warning = warning_func; + ctxt->sax->resolveEntity = resolve_func; + + // IO context struct + 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; + xmlDocPtr pDoc = xmlCtxtReadIO(ctxt, xmlIO_read_func, xmlIO_close_func, &c, + 0, 0, 0); + + if (pDoc == 0) { + throwEx(ctxt); + } + xmlFreeParserCtxt(ctxt); + return Reference< XDocument >(static_cast< CDocument* >(CNode::get((xmlNodePtr)pDoc))); + } + + Reference< XDocument > SAL_CALL CDocumentBuilder::parseSource(const InputSource& is) + throw (RuntimeException, SAXParseException, IOException) + { + // if there is an encoding specified in the input source, use it + xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; + if (is.sEncoding.getLength() > 0) { + OString oEncstr = OUStringToOString(is.sEncoding, RTL_TEXTENCODING_UTF8); + char *encstr = (char*) oEncstr.getStr(); + enc = xmlParseCharEncoding(encstr); + } + + // set up parser context + xmlParserCtxtPtr ctxt = xmlNewParserCtxt(); + // register error functions to prevent errors being printed + // on the console + ctxt->_private = this; + ctxt->sax->error = error_func; + ctxt->sax->warning = warning_func; + + // setup entity resolver binding(s) + ctxt->sax->resolveEntity = resolve_func; + xmlSetExternalEntityLoader(external_entity_loader); + + // if an input stream is provided, use it + + // use the systemID + + return Reference< XDocument >(); + } + + Reference< XDocument > SAL_CALL CDocumentBuilder::parseURI(const OUString& sUri) + throw (RuntimeException, SAXParseException, IOException) + { + xmlParserCtxtPtr ctxt = xmlNewParserCtxt(); + ctxt->_private = this; + ctxt->sax->error = error_func; + ctxt->sax->warning = warning_func; + ctxt->sax->resolveEntity = resolve_func; + // xmlSetExternalEntityLoader(external_entity_loader); + OString oUri = OUStringToOString(sUri, RTL_TEXTENCODING_UTF8); + char *uri = (char*) oUri.getStr(); + xmlDocPtr pDoc = xmlCtxtReadFile(ctxt, uri, 0, 0); + if (pDoc == 0) { + throwEx(ctxt); + } + xmlFreeParserCtxt(ctxt); + return Reference< XDocument >(static_cast< CDocument* >(CNode::get((xmlNodePtr)pDoc))); + } + + void SAL_CALL CDocumentBuilder::setEntityResolver(const Reference< XEntityResolver >& er) + throw (RuntimeException) + { + m_aEntityResolver = er; + } + + Reference< XEntityResolver > SAL_CALL CDocumentBuilder::getEntityResolver() + throw (RuntimeException) + { + return m_aEntityResolver; + } + + + void SAL_CALL CDocumentBuilder::setErrorHandler(const Reference< XErrorHandler >& eh) + throw (RuntimeException) + { + m_aErrorHandler = eh; + } +} |