diff options
Diffstat (limited to 'oox/source/mathml')
-rw-r--r-- | oox/source/mathml/export.cxx | 21 | ||||
-rw-r--r-- | oox/source/mathml/import.cxx | 114 | ||||
-rw-r--r-- | oox/source/mathml/importutils.cxx | 337 |
3 files changed, 472 insertions, 0 deletions
diff --git a/oox/source/mathml/export.cxx b/oox/source/mathml/export.cxx new file mode 100644 index 000000000..299373e2f --- /dev/null +++ b/oox/source/mathml/export.cxx @@ -0,0 +1,21 @@ +/* -*- 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/. + */ + +#include <oox/mathml/export.hxx> + +namespace oox +{ + +FormulaExportBase::FormulaExportBase() +{ +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/mathml/import.cxx b/oox/source/mathml/import.cxx new file mode 100644 index 000000000..bff603d2b --- /dev/null +++ b/oox/source/mathml/import.cxx @@ -0,0 +1,114 @@ +/* -*- 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/. + */ + +#include <oox/mathml/import.hxx> + +#include <oox/mathml/importutils.hxx> +#include <oox/core/contexthandler.hxx> +#include <oox/token/namespaces.hxx> + +#include <drawingml/textparagraph.hxx> + + +using namespace ::com::sun::star; + +namespace oox +{ + +FormulaImportBase::FormulaImportBase() +{ +} + +namespace formulaimport { + +namespace { + +class LazyMathBufferingContext : public core::ContextHandler +{ +private: + XmlStreamBuilder & m_rBuilder; + std::vector<sal_Int32> m_OpenElements; + +public: + LazyMathBufferingContext(core::ContextHandler const& rParent, + drawingml::TextParagraph & rPara); + + // com.sun.star.xml.sax.XFastContextHandler interface --------------------- + + virtual void SAL_CALL startFastElement(::sal_Int32 Element, const uno::Reference<xml::sax::XFastAttributeList>& xAttribs) override; + virtual void SAL_CALL endFastElement(::sal_Int32 Element) override; + virtual uno::Reference< xml::sax::XFastContextHandler> SAL_CALL createFastChildContext(::sal_Int32 Element, const uno::Reference<xml::sax::XFastAttributeList >& xAttribs) override; + virtual void SAL_CALL characters(const OUString& rChars) override; + +}; + +} + +LazyMathBufferingContext::LazyMathBufferingContext( + core::ContextHandler const& rParent, drawingml::TextParagraph & rPara) + : core::ContextHandler(rParent) + , m_rBuilder(rPara.GetMathXml()) +{ +} + +void SAL_CALL LazyMathBufferingContext::startFastElement( + sal_Int32 const nElement, + uno::Reference<xml::sax::XFastAttributeList> const& xAttrs) +{ + if (0 < m_OpenElements.size()) // ignore a14:m + { // ignore outer oMathPara + if (1 != m_OpenElements.size() || OOX_TOKEN(officeMath, oMathPara) != nElement) + { + m_rBuilder.appendOpeningTag(nElement, xAttrs); + } + } + m_OpenElements.push_back(nElement); +} + +void SAL_CALL LazyMathBufferingContext::endFastElement(sal_Int32 const nElement) +{ + m_OpenElements.pop_back(); + if (0 < m_OpenElements.size()) // ignore a14:m + { // ignore outer oMathPara + if (1 != m_OpenElements.size() || OOX_TOKEN(officeMath, oMathPara) != nElement) + { + m_rBuilder.appendClosingTag(nElement); + } + } +} + +uno::Reference<xml::sax::XFastContextHandler> SAL_CALL +LazyMathBufferingContext::createFastChildContext(sal_Int32 const, + uno::Reference<xml::sax::XFastAttributeList> const&) +{ + return this; +} + +void SAL_CALL LazyMathBufferingContext::characters(OUString const& rChars) +{ + if (0 < m_OpenElements.size()) // ignore a14:m + { + if (m_OpenElements.back() == OOX_TOKEN(officeMath, t)) + { + m_rBuilder.appendCharacters(rChars); + } + } +} + +} // namespace oox::formulaimport + +rtl::Reference<core::ContextHandler> CreateLazyMathBufferingContext( + core::ContextHandler const& rParent, drawingml::TextParagraph & rPara) +{ + return new formulaimport::LazyMathBufferingContext(rParent, rPara); +} + +} // namespace oox + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/mathml/importutils.cxx b/oox/source/mathml/importutils.cxx new file mode 100644 index 000000000..d2727d17e --- /dev/null +++ b/oox/source/mathml/importutils.cxx @@ -0,0 +1,337 @@ +/* -*- 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/. + */ + +#include <oox/mathml/importutils.hxx> + +#include <assert.h> + +#include <com/sun/star/xml/FastAttribute.hpp> +#include <com/sun/star/xml/sax/XFastAttributeList.hpp> +#include <oox/token/tokenmap.hxx> +#include <oox/token/tokens.hxx> +#include <oox/token/namespaces.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> + +#define OPENING( token ) XML_STREAM_OPENING( token ) +#define CLOSING( token ) XML_STREAM_CLOSING( token ) + +using namespace com::sun::star; + +namespace oox::formulaimport +{ + +namespace +{ +// a class that inherits from AttributeList, builds the internal data and then will be sliced off +// during conversion to the base class +class AttributeListBuilder + : public XmlStream::AttributeList +{ +public: + explicit AttributeListBuilder( const uno::Reference< xml::sax::XFastAttributeList >& a ); +}; + +AttributeListBuilder::AttributeListBuilder( const uno::Reference< xml::sax::XFastAttributeList >& a ) +{ + if( a.get() == nullptr ) + return; + const uno::Sequence< xml::FastAttribute > aFastAttrSeq = a->getFastAttributes(); + for( const xml::FastAttribute& rFastAttr : aFastAttrSeq ) + { + attrs[ rFastAttr.Token ] = rFastAttr.Value; + } +} + +OString tokenToString( int token ) +{ + uno::Sequence< sal_Int8 > const & aTokenNameSeq = StaticTokenMap::get().getUtf8TokenName( token & TOKEN_MASK ); + OString tokenname( reinterpret_cast< const char* >( aTokenNameSeq.getConstArray() ), aTokenNameSeq.getLength() ); + if( tokenname.isEmpty()) + tokenname = "???"; + int nmsp = ( token & NMSP_MASK & ~( TAG_OPENING | TAG_CLOSING )); +#if 0 // this is awfully long + OString namespacename = StaticNamespaceMap::get().count( nmsp ) != 0 + ? StaticNamespaceMap::get()[ nmsp ] : OString( "???" ); +#else + OString namespacename; + // only few are needed actually + switch( nmsp ) + { + case NMSP_officeMath: + namespacename = "m"; + break; + case NMSP_doc: + namespacename = "w"; + break; + default: + namespacename = "?"; + break; + } +#endif + if( token == OPENING( token )) + return "<" + namespacename + ":" + tokenname + ">"; + if( token == CLOSING( token )) + return "</" + namespacename + ":" + tokenname + ">"; + // just the name itself, not specified whether opening or closing + return namespacename + ":" + tokenname; +} + +} // namespace + +OUString& XmlStream::AttributeList::operator[] (int token) +{ + return attrs[token]; +} + +OUString XmlStream::AttributeList::attribute( int token, const OUString& def ) const +{ + std::map< int, OUString >::const_iterator find = attrs.find( token ); + if( find != attrs.end()) + return find->second; + return def; +} + +bool XmlStream::AttributeList::attribute( int token, bool def ) const +{ + std::map< int, OUString >::const_iterator find = attrs.find( token ); + if( find != attrs.end()) + { + const OUString sValue = find->second; + if( sValue.equalsIgnoreAsciiCase("true") || + sValue.equalsIgnoreAsciiCase("on") || + sValue.equalsIgnoreAsciiCase("t") || + sValue.equalsIgnoreAsciiCase("1") ) + return true; + if( sValue.equalsIgnoreAsciiCase("false") || + sValue.equalsIgnoreAsciiCase("off") || + sValue.equalsIgnoreAsciiCase("f") || + sValue.equalsIgnoreAsciiCase("0") ) + return false; + SAL_WARN( "oox.xmlstream", "Cannot convert \'" << sValue << "\' to bool." ); + } + return def; +} + +sal_Unicode XmlStream::AttributeList::attribute( int token, sal_Unicode def ) const +{ + std::map< int, OUString >::const_iterator find = attrs.find( token ); + if( find != attrs.end()) + { + if( !find->second.isEmpty() ) + { + if( find->second.getLength() != 1 ) + SAL_WARN( "oox.xmlstream", "Cannot convert \'" << find->second << "\' to sal_Unicode, stripping." ); + return find->second[ 0 ]; + } + } + return def; +} + +XmlStream::Tag::Tag( int t, const uno::Reference< xml::sax::XFastAttributeList >& a ) +: token( t ) +, attributes( AttributeListBuilder( a )) +{ +} + +XmlStream::Tag::Tag( int t, const AttributeList& a ) +: token( t ) +, attributes( a ) +{ +} + +XmlStream::Tag::operator bool() const +{ + return token != XML_TOKEN_INVALID; +} + +XmlStream::XmlStream() +: pos( 0 ) +{ + // make sure our extra bit does not conflict with values used by oox + assert( TAG_OPENING > ( 1024 << NMSP_SHIFT )); +} + +bool XmlStream::atEnd() const +{ + return pos >= tags.size(); +} + +XmlStream::Tag XmlStream::currentTag() const +{ + if( pos >= tags.size()) + return Tag(); + return tags[ pos ]; +} + +int XmlStream::currentToken() const +{ + if( pos >= tags.size()) + return XML_TOKEN_INVALID; + return tags[ pos ].token; +} + +void XmlStream::moveToNextTag() +{ + if( pos < tags.size()) + ++pos; +} + +XmlStream::Tag XmlStream::ensureOpeningTag( int token ) +{ + return checkTag( OPENING( token ), false ); +} + +XmlStream::Tag XmlStream::checkOpeningTag( int token ) +{ + return checkTag( OPENING( token ), true ); +} + +void XmlStream::ensureClosingTag( int token ) +{ + checkTag( CLOSING( token ), false ); +} + +XmlStream::Tag XmlStream::checkTag( int token, bool optional ) +{ + // either it's the following tag, or find it + int savedPos = pos; + if( optional ) + { // avoid printing debug messages about skipping tags if the optional one + // will not be found and the position will be reset back + if( currentToken() != token && !findTagInternal( token, true )) + { + pos = savedPos; + return Tag(); + } + } + if( currentToken() == token || findTag( token )) + { + Tag ret = currentTag(); + moveToNextTag(); + return ret; // ok + } + if( optional ) + { // not a problem, just rewind + pos = savedPos; + return Tag(); + } + SAL_WARN( "oox.xmlstream", "Expected tag " << tokenToString( token ) << " not found." ); + return Tag(); +} + +bool XmlStream::findTag( int token ) +{ + return findTagInternal( token, false ); +} + +bool XmlStream::findTagInternal( int token, bool silent ) +{ + int depth = 0; + for(; + !atEnd(); + moveToNextTag()) + { + if( depth > 0 ) // we're inside a nested element, skip those + { + if( currentToken() == OPENING( currentToken())) + { + if( !silent ) + SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken())); + ++depth; + } + else if( currentToken() == CLOSING( currentToken())) + { + if( !silent ) + SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken())); + --depth; + } + else + { + if( !silent ) + SAL_WARN( "oox.xmlstream", "Malformed token " << currentToken() << " (" + << tokenToString( currentToken()) << ")" ); + abort(); + } + continue; + } + if( currentToken() == token ) + return true; // ok, found + if( currentToken() == CLOSING( currentToken())) + return false; // that would be leaving current element, so not found + if( currentToken() == OPENING( currentToken())) + { + if( !silent ) + SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken())); + ++depth; + } + else + abort(); + } + if( !silent ) + SAL_WARN( "oox.xmlstream", "Unexpected end of stream reached." ); + return false; +} + +void XmlStream::skipElementInternal( int token, bool silent ) +{ + int closing = ( token & ~TAG_OPENING ) | TAG_CLOSING; // make it a closing tag + assert( currentToken() == OPENING( token )); + if( !silent ) + SAL_INFO( "oox.xmlstream", "Skipping unexpected element " << tokenToString( currentToken())); + moveToNextTag(); + // and just find the matching closing tag + if( findTag( closing )) + { + if( !silent ) + SAL_INFO( "oox.xmlstream", "Skipped unexpected element " << tokenToString( token )); + moveToNextTag(); // and skip it too + return; + } + // this one is an unexpected problem, do not silent it + SAL_WARN( "oox.xmlstream", "Expected end of element " << tokenToString( token ) << " not found." ); +} + +void XmlStream::handleUnexpectedTag() +{ + if( atEnd()) + return; + if( currentToken() == CLOSING( currentToken())) + { + SAL_INFO( "oox.xmlstream", "Skipping unexpected tag " << tokenToString( currentToken())); + moveToNextTag(); // just skip it + return; + } + skipElementInternal( currentToken(), false ); // otherwise skip the entire element +} + +void XmlStreamBuilder::appendOpeningTag( int token, const uno::Reference< xml::sax::XFastAttributeList >& attrs ) +{ + tags.emplace_back( OPENING( token ), attrs ); +} + +void XmlStreamBuilder::appendOpeningTag( int token, const AttributeList& attrs ) +{ + tags.emplace_back( OPENING( token ), attrs ); +} + +void XmlStreamBuilder::appendClosingTag( int token ) +{ + tags.emplace_back( CLOSING( token )); +} + +void XmlStreamBuilder::appendCharacters( const OUString& chars ) +{ + assert( !tags.empty()); + tags.back().text += chars; +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |