|  | /************************************************************** | 
|  | * | 
|  | * 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 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, | 
|  | * software distributed under the License is distributed on an | 
|  | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
|  | * KIND, either express or implied.  See the License for the | 
|  | * specific language governing permissions and limitations | 
|  | * under the License. | 
|  | * | 
|  | *************************************************************/ | 
|  |  | 
|  |  | 
|  |  | 
|  | // MARKER(update_precomp.py): autogen include statement, do not remove | 
|  | #include "precompiled_xmlsecurity.hxx" | 
|  |  | 
|  | #include <rtl/ustring.hxx> | 
|  |  | 
|  | #include "saxhelper.hxx" | 
|  | #include "libxml/parserInternals.h" | 
|  |  | 
|  | #ifndef XMLSEC_NO_XSLT | 
|  | #include "libxslt/xslt.h" | 
|  | #endif | 
|  |  | 
|  | namespace cssu = com::sun::star::uno; | 
|  | namespace cssxs = com::sun::star::xml::sax; | 
|  | namespace cssxcsax = com::sun::star::xml::csax; | 
|  |  | 
|  | /** | 
|  | * The return value is NULL terminated. The application has the responsibilty to | 
|  | * deallocte the return value. | 
|  | */ | 
|  | xmlChar* ous_to_xmlstr( const rtl::OUString& oustr ) | 
|  | { | 
|  | rtl::OString ostr = rtl::OUStringToOString( oustr , RTL_TEXTENCODING_UTF8 ) ; | 
|  | return xmlStrndup( ( xmlChar* )ostr.getStr(), ( int )ostr.getLength() ) ; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * The return value is NULL terminated. The application has the responsibilty to | 
|  | * deallocte the return value. | 
|  | */ | 
|  | xmlChar* ous_to_nxmlstr( const rtl::OUString& oustr, int& length ) | 
|  | { | 
|  | rtl::OString ostr = rtl::OUStringToOString( oustr , RTL_TEXTENCODING_UTF8 ) ; | 
|  | length = ostr.getLength(); | 
|  |  | 
|  | return xmlStrndup( ( xmlChar* )ostr.getStr(), length ) ; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * The input parameter isn't necessaryly NULL terminated. | 
|  | */ | 
|  | rtl::OUString xmlchar_to_ous( const xmlChar* pChar, int length ) | 
|  | { | 
|  | if( pChar != NULL ) | 
|  | { | 
|  | return rtl::OUString( ( sal_Char* )pChar , length , RTL_TEXTENCODING_UTF8 ) ; | 
|  | } | 
|  | else | 
|  | { | 
|  | return rtl::OUString() ; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * The input parameter is NULL terminated | 
|  | */ | 
|  | rtl::OUString xmlstr_to_ous( const xmlChar* pStr ) | 
|  | { | 
|  | if( pStr != NULL ) | 
|  | { | 
|  | return xmlchar_to_ous( pStr , xmlStrlen( pStr ) ) ; | 
|  | } | 
|  | else | 
|  | { | 
|  | return rtl::OUString() ; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * The return value and the referenced value must be NULL terminated. | 
|  | * The application has the responsibilty to deallocte the return value. | 
|  | */ | 
|  | const xmlChar** attrlist_to_nxmlstr( const cssu::Sequence< cssxcsax::XMLAttribute >& aAttributes ) | 
|  | { | 
|  | xmlChar* attname = NULL ; | 
|  | xmlChar* attvalue = NULL ; | 
|  | const xmlChar** attrs = NULL ; | 
|  | rtl::OUString oustr ; | 
|  |  | 
|  | sal_Int32 nLength = aAttributes.getLength();; | 
|  |  | 
|  | if( nLength != 0 ) | 
|  | { | 
|  | attrs = ( const xmlChar** )xmlMalloc( ( nLength * 2 + 2 ) * sizeof( xmlChar* ) ) ; | 
|  | } | 
|  | else | 
|  | { | 
|  | return NULL ; | 
|  | } | 
|  |  | 
|  | for( int i = 0 , j = 0 ; j < nLength ; ++j ) | 
|  | { | 
|  | attname = ous_to_xmlstr( aAttributes[j].sName ) ; | 
|  | attvalue = ous_to_xmlstr( aAttributes[j].sValue ) ; | 
|  |  | 
|  | if( attname != NULL && attvalue != NULL ) | 
|  | { | 
|  | attrs[i++] = attname ; | 
|  | attrs[i++] = attvalue ; | 
|  | attrs[i] = NULL ; | 
|  | attrs[i+1] = NULL ; | 
|  | } | 
|  | else | 
|  | { | 
|  | if( attname != NULL ) | 
|  | xmlFree( attname ) ; | 
|  | if( attvalue != NULL ) | 
|  | xmlFree( attvalue ) ; | 
|  | } | 
|  | } | 
|  |  | 
|  | return attrs ; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Constructor | 
|  | * | 
|  | * In this constructor, a libxml sax parser context is initialized. a libxml | 
|  | * default sax handler is initialized with the context. | 
|  | */ | 
|  | SAXHelper::SAXHelper( ) | 
|  | : m_pParserCtxt( NULL ), | 
|  | m_pSaxHandler( NULL ) | 
|  | { | 
|  | xmlInitParser() ; | 
|  | LIBXML_TEST_VERSION ; | 
|  |  | 
|  | /* | 
|  | * compile error: | 
|  | * xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS ; | 
|  | */ | 
|  | xmlSubstituteEntitiesDefault( 1 ) ; | 
|  |  | 
|  | #ifndef XMLSEC_NO_XSLT | 
|  | xmlIndentTreeOutput = 1 ; | 
|  | #endif /* XMLSEC_NO_XSLT */ | 
|  |  | 
|  | m_pParserCtxt = xmlNewParserCtxt() ; | 
|  |  | 
|  | /* | 
|  | * i41748 | 
|  | * | 
|  | * mmi : re-initialize the SAX handler to version 1 | 
|  | */ | 
|  |  | 
|  | xmlSAXVersion(m_pParserCtxt->sax, 1); | 
|  |  | 
|  | /* end */ | 
|  |  | 
|  | if( m_pParserCtxt->inputTab[0] != NULL ) | 
|  | { | 
|  | m_pParserCtxt->inputTab[0] = NULL ; | 
|  | } | 
|  |  | 
|  | if( m_pParserCtxt == NULL ) | 
|  | { | 
|  | #ifndef XMLSEC_NO_XSLT | 
|  | xsltCleanupGlobals() ; | 
|  | #endif | 
|  | //      see issue i74334, we cannot call xmlCleanupParser when libxml is still used | 
|  | //		in other parts of the office. | 
|  | //		xmlCleanupParser() ; | 
|  | throw cssu::RuntimeException() ; | 
|  | } | 
|  | else if( m_pParserCtxt->sax == NULL ) | 
|  | { | 
|  | xmlFreeParserCtxt( m_pParserCtxt ) ; | 
|  |  | 
|  | #ifndef XMLSEC_NO_XSLT | 
|  | xsltCleanupGlobals() ; | 
|  | #endif | 
|  | //      see issue i74334, we cannot call xmlCleanupParser when libxml is still used | 
|  | //		in other parts of the office. | 
|  | //		xmlCleanupParser() ; | 
|  | m_pParserCtxt = NULL ; | 
|  | throw cssu::RuntimeException() ; | 
|  | } | 
|  | else | 
|  | { | 
|  | m_pSaxHandler = m_pParserCtxt->sax ; | 
|  |  | 
|  | //Adjust the context | 
|  | m_pParserCtxt->recovery = 1 ; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Destructor | 
|  | * | 
|  | * In this destructor, a libxml sax parser context is desturcted. The XML tree | 
|  | * in the context is not deallocated because the tree is bind with a document | 
|  | * model by the setTargetDocument method, which delegate the target document to | 
|  | * destruct the xml tree. | 
|  | */ | 
|  | SAXHelper::~SAXHelper() { | 
|  | if( m_pParserCtxt != NULL ) | 
|  | { | 
|  | /* | 
|  | * In the situation that no object refer the Document, this destructor | 
|  | * must deallocate the Document memory | 
|  | */ | 
|  | if( m_pSaxHandler == m_pParserCtxt->sax ) | 
|  | { | 
|  | m_pSaxHandler = NULL ; | 
|  | } | 
|  |  | 
|  | xmlFreeParserCtxt( m_pParserCtxt ) ; | 
|  | m_pParserCtxt = NULL ; | 
|  | } | 
|  |  | 
|  | if( m_pSaxHandler != NULL ) | 
|  | { | 
|  | xmlFree( m_pSaxHandler ) ; | 
|  | m_pSaxHandler = NULL ; | 
|  | } | 
|  | //      see issue i74334, we cannot call xmlCleanupParser when libxml is still used | 
|  | //		in other parts of the office. | 
|  | //	xmlCleanupParser() ; | 
|  | } | 
|  |  | 
|  | xmlNodePtr SAXHelper::getCurrentNode() | 
|  | { | 
|  | return m_pParserCtxt->node; | 
|  | } | 
|  |  | 
|  | void SAXHelper::setCurrentNode(const xmlNodePtr pNode) | 
|  | { | 
|  | /* | 
|  | * This is really a black trick. | 
|  | * When the current node is replaced, the nodeTab | 
|  | * stack's top has to been replaced with the same | 
|  | * node, in order to make compatibility. | 
|  | */ | 
|  | m_pParserCtxt->nodeTab[m_pParserCtxt->nodeNr - 1] | 
|  | = m_pParserCtxt->node | 
|  | = pNode; | 
|  | } | 
|  |  | 
|  | xmlDocPtr SAXHelper::getDocument() | 
|  | { | 
|  | return m_pParserCtxt->myDoc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * XDocumentHandler -- start an xml document | 
|  | */ | 
|  | void SAXHelper::startDocument( void ) | 
|  | throw( cssxs::SAXException , cssu::RuntimeException ) | 
|  | { | 
|  | /* | 
|  | * Adjust inputTab | 
|  | */ | 
|  | xmlParserInputPtr pInput = xmlNewInputStream( m_pParserCtxt ) ; | 
|  |  | 
|  | if( m_pParserCtxt->inputTab != NULL && m_pParserCtxt->inputMax != 0 ) | 
|  | { | 
|  | m_pParserCtxt->inputTab[0] = pInput ; | 
|  | m_pParserCtxt->input = pInput ; | 
|  | } | 
|  |  | 
|  | m_pSaxHandler->startDocument( m_pParserCtxt ) ; | 
|  |  | 
|  | if( m_pParserCtxt == NULL || m_pParserCtxt->myDoc == NULL ) | 
|  | { | 
|  | throw cssu::RuntimeException() ; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * XDocumentHandler -- end an xml document | 
|  | */ | 
|  | void SAXHelper::endDocument( void ) | 
|  | throw( cssxs::SAXException , cssu::RuntimeException ) | 
|  | { | 
|  | m_pSaxHandler->endDocument( m_pParserCtxt ) ; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * XDocumentHandler -- start an xml element | 
|  | */ | 
|  | void SAXHelper::startElement( | 
|  | const rtl::OUString& aName, | 
|  | const cssu::Sequence< cssxcsax::XMLAttribute >& aAttributes ) | 
|  | throw( cssxs::SAXException , cssu::RuntimeException ) | 
|  | { | 
|  | const xmlChar* fullName = NULL ; | 
|  | const xmlChar** attrs = NULL ; | 
|  |  | 
|  | fullName = ous_to_xmlstr( aName ) ; | 
|  | attrs = attrlist_to_nxmlstr( aAttributes ) ; | 
|  |  | 
|  | if( fullName != NULL || attrs != NULL ) | 
|  | { | 
|  | m_pSaxHandler->startElement( m_pParserCtxt , fullName , attrs ) ; | 
|  | } | 
|  |  | 
|  | if( fullName != NULL ) | 
|  | { | 
|  | xmlFree( ( xmlChar* )fullName ) ; | 
|  | fullName = NULL ; | 
|  | } | 
|  |  | 
|  | if( attrs != NULL ) | 
|  | { | 
|  | for( int i = 0 ; attrs[i] != NULL ; ++i ) | 
|  | { | 
|  | xmlFree( ( xmlChar* )attrs[i] ) ; | 
|  | attrs[i] = NULL ; | 
|  | } | 
|  |  | 
|  | xmlFree( ( void* ) attrs ) ; | 
|  | attrs = NULL ; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * XDocumentHandler -- end an xml element | 
|  | */ | 
|  | void SAXHelper::endElement( const rtl::OUString& aName ) | 
|  | throw( cssxs::SAXException , cssu::RuntimeException ) | 
|  | { | 
|  | xmlChar* fullname = NULL ; | 
|  |  | 
|  | fullname = ous_to_xmlstr( aName ) ; | 
|  | m_pSaxHandler->endElement( m_pParserCtxt , fullname ) ; | 
|  |  | 
|  | if( fullname != NULL ) | 
|  | { | 
|  | xmlFree( ( xmlChar* )fullname ) ; | 
|  | fullname = NULL ; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * XDocumentHandler -- an xml element or cdata characters | 
|  | */ | 
|  | void SAXHelper::characters( const rtl::OUString& aChars ) | 
|  | throw( cssxs::SAXException , cssu::RuntimeException ) | 
|  | { | 
|  | const xmlChar* chars = NULL ; | 
|  | int length = 0 ; | 
|  |  | 
|  | chars = ous_to_nxmlstr( aChars, length ) ; | 
|  | m_pSaxHandler->characters( m_pParserCtxt , chars , length ) ; | 
|  |  | 
|  | if( chars != NULL ) | 
|  | { | 
|  | xmlFree( ( xmlChar* )chars ) ; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * XDocumentHandler -- ignorable xml white space | 
|  | */ | 
|  | void SAXHelper::ignorableWhitespace( const rtl::OUString& aWhitespaces ) | 
|  | throw( cssxs::SAXException , cssu::RuntimeException ) | 
|  | { | 
|  | const xmlChar* chars = NULL ; | 
|  | int length = 0 ; | 
|  |  | 
|  | chars = ous_to_nxmlstr( aWhitespaces, length ) ; | 
|  | m_pSaxHandler->ignorableWhitespace( m_pParserCtxt , chars , length ) ; | 
|  |  | 
|  | if( chars != NULL ) | 
|  | { | 
|  | xmlFree( ( xmlChar* )chars ) ; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * XDocumentHandler -- preaorocessing instruction | 
|  | */ | 
|  | void SAXHelper::processingInstruction( | 
|  | const rtl::OUString& aTarget, | 
|  | const rtl::OUString& aData ) | 
|  | throw( cssxs::SAXException , cssu::RuntimeException ) | 
|  | { | 
|  | xmlChar* target = NULL ; | 
|  | xmlChar* data = NULL ; | 
|  |  | 
|  | target = ous_to_xmlstr( aTarget ) ; | 
|  | data = ous_to_xmlstr( aData ) ; | 
|  |  | 
|  | m_pSaxHandler->processingInstruction( m_pParserCtxt , target , data ) ; | 
|  |  | 
|  | if( target != NULL ) | 
|  | { | 
|  | xmlFree( ( xmlChar* )target ) ; | 
|  | target = NULL ; | 
|  | } | 
|  |  | 
|  | if( data != NULL ) | 
|  | { | 
|  | xmlFree( ( xmlChar* )data ) ; | 
|  | data = NULL ; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * XDocumentHandler -- set document locator | 
|  | * In this case, locator is useless. | 
|  | */ | 
|  | void SAXHelper::setDocumentLocator( | 
|  | const cssu::Reference< cssxs::XLocator > &) | 
|  | throw( cssxs::SAXException , cssu::RuntimeException ) | 
|  | { | 
|  | //--Pseudo code if necessary | 
|  | //--m_pSaxLocator is a member defined as xmlSAXHabdlerPtr | 
|  | //--m_pSaxLocatorHdl is a member defined as Sax_Locator | 
|  |  | 
|  | //if( m_pSaxLocator != NULL ) { | 
|  | //	//Deallocate the memory | 
|  | //} | 
|  | //if( m_pSaxLocatorHdl != NULL ) { | 
|  | //	//Deallocate the memory | 
|  | //} | 
|  |  | 
|  | //m_pSaxLocatorHdl = new Sax_Locator( xLocator ) ; | 
|  | //m_pSaxLocator = { m_pSaxLocatorHdl->getPublicId , m_pSaxLocatorHdl->getSystemId , m_pSaxLocatorHdl->getLineNumber , m_pSaxLocatorHdl->getColumnNumber } ; | 
|  |  | 
|  | //m_pSaxHandler->setDocumentLocator( m_pParserCtxt , m_pSaxLocator ) ; | 
|  | } | 
|  |  |