2011-09-01 12:36:04 -05:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
|
|
/*
|
2013-04-19 15:10:42 -05:00
|
|
|
* This file is part of the LibreOffice project.
|
2011-09-01 12:36:04 -05:00
|
|
|
*
|
2013-04-19 15:10:42 -05:00
|
|
|
* 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/.
|
2011-09-01 12:36:04 -05:00
|
|
|
*/
|
|
|
|
|
2011-11-18 14:06:54 -06:00
|
|
|
#include "oox/mathml/importutils.hxx"
|
|
|
|
|
|
|
|
#include <assert.h>
|
2011-11-25 00:26:10 -06:00
|
|
|
#include <stdio.h>
|
|
|
|
|
2011-11-29 12:05:52 -06:00
|
|
|
#include <oox/token/namespacemap.hxx>
|
|
|
|
#include <oox/token/tokenmap.hxx>
|
2011-11-18 11:09:43 -06:00
|
|
|
#include <oox/token/tokens.hxx>
|
|
|
|
#include <oox/token/namespaces.hxx>
|
2012-09-17 17:11:09 -05:00
|
|
|
#include <rtl/ustring.hxx>
|
2011-11-29 12:05:52 -06:00
|
|
|
|
2011-12-02 10:38:51 -06:00
|
|
|
#define OPENING( token ) XML_STREAM_OPENING( token )
|
|
|
|
#define CLOSING( token ) XML_STREAM_CLOSING( token )
|
2011-11-18 11:09:43 -06:00
|
|
|
|
|
|
|
using namespace com::sun::star;
|
2011-09-01 12:36:04 -05:00
|
|
|
|
2011-11-18 14:06:54 -06:00
|
|
|
namespace oox
|
2011-11-18 11:09:43 -06:00
|
|
|
{
|
|
|
|
|
2011-11-18 14:06:54 -06:00
|
|
|
namespace formulaimport
|
2011-11-18 11:09:43 -06:00
|
|
|
{
|
|
|
|
|
2011-11-24 09:09:42 -06:00
|
|
|
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:
|
|
|
|
AttributeListBuilder( const uno::Reference< xml::sax::XFastAttributeList >& a );
|
|
|
|
};
|
|
|
|
|
|
|
|
AttributeListBuilder::AttributeListBuilder( const uno::Reference< xml::sax::XFastAttributeList >& a )
|
|
|
|
{
|
|
|
|
if( a.get() == NULL )
|
|
|
|
return;
|
|
|
|
uno::Sequence< xml::FastAttribute > aFastAttrSeq = a->getFastAttributes();
|
|
|
|
const xml::FastAttribute* pFastAttr = aFastAttrSeq.getConstArray();
|
|
|
|
sal_Int32 nFastAttrLength = aFastAttrSeq.getLength();
|
|
|
|
for( int i = 0;
|
|
|
|
i < nFastAttrLength;
|
|
|
|
++i )
|
|
|
|
{
|
|
|
|
attrs[ pFastAttr[ i ].Token ] = pFastAttr[ i ].Value;
|
|
|
|
}
|
|
|
|
}
|
2011-11-29 12:05:52 -06:00
|
|
|
|
|
|
|
static OUString tokenToString( int token )
|
|
|
|
{
|
|
|
|
OUString tokenname = StaticTokenMap::get().getUnicodeTokenName( token & TOKEN_MASK );
|
|
|
|
if( tokenname.isEmpty())
|
2013-01-24 04:14:21 -06:00
|
|
|
tokenname = "???";
|
2011-11-29 12:05:52 -06:00
|
|
|
int nmsp = ( token & NMSP_MASK & ~( TAG_OPENING | TAG_CLOSING ));
|
|
|
|
#if 0 // this is awfully long
|
|
|
|
OUString namespacename = StaticNamespaceMap::get().count( nmsp ) != 0
|
2013-01-24 04:14:21 -06:00
|
|
|
? StaticNamespaceMap::get()[ nmsp ] : OUString( "???" );
|
2011-11-29 12:05:52 -06:00
|
|
|
#else
|
|
|
|
OUString namespacename;
|
|
|
|
// only few are needed actually
|
|
|
|
switch( nmsp )
|
|
|
|
{
|
|
|
|
case NMSP_officeMath:
|
2013-01-24 04:14:21 -06:00
|
|
|
namespacename = "m";
|
2011-11-29 12:05:52 -06:00
|
|
|
break;
|
|
|
|
case NMSP_doc:
|
2013-01-24 04:14:21 -06:00
|
|
|
namespacename = "w";
|
2011-11-29 12:05:52 -06:00
|
|
|
break;
|
|
|
|
default:
|
2013-01-24 04:14:21 -06:00
|
|
|
namespacename = "?";
|
2011-11-29 12:05:52 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if( token == OPENING( token ))
|
2013-01-24 04:14:21 -06:00
|
|
|
return "<" + namespacename + ":" + tokenname + ">";
|
2011-11-29 12:05:52 -06:00
|
|
|
if( token == CLOSING( token ))
|
2013-01-24 04:14:21 -06:00
|
|
|
return "</" + namespacename + ":" + tokenname + ">";
|
2011-11-29 12:05:52 -06:00
|
|
|
// just the name itself, not specified whether opening or closing
|
2013-01-24 04:14:21 -06:00
|
|
|
return namespacename + ":" + tokenname;
|
2011-11-29 12:05:52 -06:00
|
|
|
}
|
|
|
|
|
2011-11-24 09:09:42 -06:00
|
|
|
} // namespace
|
|
|
|
|
2012-07-23 09:59:13 -05:00
|
|
|
OUString& XmlStream::AttributeList::operator[] (int token)
|
|
|
|
{
|
|
|
|
return attrs[token];
|
|
|
|
}
|
|
|
|
|
2013-04-07 05:06:47 -05:00
|
|
|
OUString XmlStream::AttributeList::attribute( int token, const OUString& def ) const
|
2011-11-24 09:09:42 -06:00
|
|
|
{
|
2013-02-02 14:23:45 -06:00
|
|
|
std::map< int, OUString >::const_iterator find = attrs.find( token );
|
2011-11-24 09:09:42 -06:00
|
|
|
if( find != attrs.end())
|
|
|
|
return find->second;
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool XmlStream::AttributeList::attribute( int token, bool def ) const
|
|
|
|
{
|
2013-02-02 14:23:45 -06:00
|
|
|
std::map< int, OUString >::const_iterator find = attrs.find( token );
|
2011-11-24 09:09:42 -06:00
|
|
|
if( find != attrs.end())
|
|
|
|
{
|
2013-02-02 14:23:45 -06:00
|
|
|
const OUString sValue = find->second;
|
2013-03-19 05:32:06 -05:00
|
|
|
if( sValue.equalsIgnoreAsciiCase("true") ||
|
|
|
|
sValue.equalsIgnoreAsciiCase("on") ||
|
|
|
|
sValue.equalsIgnoreAsciiCase("t") ||
|
|
|
|
sValue.equalsIgnoreAsciiCase("1") )
|
2011-11-24 09:09:42 -06:00
|
|
|
return true;
|
2013-03-19 05:32:06 -05:00
|
|
|
if( sValue.equalsIgnoreAsciiCase("false") ||
|
|
|
|
sValue.equalsIgnoreAsciiCase("off") ||
|
|
|
|
sValue.equalsIgnoreAsciiCase("f") ||
|
|
|
|
sValue.equalsIgnoreAsciiCase("0") )
|
2011-11-24 09:09:42 -06:00
|
|
|
return false;
|
2012-02-19 08:27:29 -06:00
|
|
|
SAL_WARN( "oox.xmlstream", "Cannot convert \'" << sValue << "\' to bool." );
|
2011-11-24 09:09:42 -06:00
|
|
|
}
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
2011-11-29 09:19:53 -06:00
|
|
|
sal_Unicode XmlStream::AttributeList::attribute( int token, sal_Unicode def ) const
|
|
|
|
{
|
2013-02-02 14:23:45 -06:00
|
|
|
std::map< int, OUString >::const_iterator find = attrs.find( token );
|
2011-11-29 09:19:53 -06:00
|
|
|
if( find != attrs.end())
|
|
|
|
{
|
2012-01-01 08:55:53 -06:00
|
|
|
if( !find->second.isEmpty() )
|
2011-11-29 09:19:53 -06:00
|
|
|
{
|
2012-01-30 07:07:42 -06:00
|
|
|
if( find->second.getLength() != 1 )
|
|
|
|
SAL_WARN( "oox.xmlstream", "Cannot convert \'" << find->second << "\' to sal_Unicode, stripping." );
|
2011-11-29 09:19:53 -06:00
|
|
|
return find->second[ 0 ];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
2013-04-07 05:06:47 -05:00
|
|
|
XmlStream::Tag::Tag( int t, const uno::Reference< xml::sax::XFastAttributeList >& a, const OUString& txt )
|
2011-11-24 09:09:42 -06:00
|
|
|
: token( t )
|
|
|
|
, attributes( AttributeListBuilder( a ))
|
|
|
|
, text( txt )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-07-23 09:59:13 -05:00
|
|
|
XmlStream::Tag::Tag( int t, const AttributeList& a )
|
|
|
|
: token( t )
|
|
|
|
, attributes( a )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-11-24 09:09:42 -06:00
|
|
|
|
2011-11-25 06:18:03 -06:00
|
|
|
XmlStream::Tag::operator bool() const
|
2011-11-24 06:19:57 -06:00
|
|
|
{
|
|
|
|
return token != XML_TOKEN_INVALID;
|
|
|
|
}
|
|
|
|
|
2011-11-18 11:09:43 -06:00
|
|
|
XmlStream::XmlStream()
|
2011-11-21 10:32:09 -06:00
|
|
|
: pos( 0 )
|
2011-11-18 11:09:43 -06:00
|
|
|
{
|
|
|
|
// make sure our extra bit does not conflict with values used by oox
|
|
|
|
assert( TAG_OPENING > ( 1024 << NMSP_SHIFT ));
|
|
|
|
}
|
|
|
|
|
2011-11-21 10:32:09 -06:00
|
|
|
bool XmlStream::atEnd() const
|
2011-11-18 11:09:43 -06:00
|
|
|
{
|
2011-11-21 10:32:09 -06:00
|
|
|
return pos >= tags.size();
|
2011-11-18 11:09:43 -06:00
|
|
|
}
|
|
|
|
|
2011-11-21 10:32:09 -06:00
|
|
|
XmlStream::Tag XmlStream::currentTag() const
|
2011-11-18 11:09:43 -06:00
|
|
|
{
|
2011-11-21 10:32:09 -06:00
|
|
|
if( pos >= tags.size())
|
|
|
|
return Tag();
|
|
|
|
return tags[ pos ];
|
2011-11-18 11:09:43 -06:00
|
|
|
}
|
|
|
|
|
2011-11-21 10:32:09 -06:00
|
|
|
int XmlStream::currentToken() const
|
2011-11-18 11:09:43 -06:00
|
|
|
{
|
2011-11-21 10:32:09 -06:00
|
|
|
if( pos >= tags.size())
|
|
|
|
return XML_TOKEN_INVALID;
|
|
|
|
return tags[ pos ].token;
|
2011-11-18 11:09:43 -06:00
|
|
|
}
|
|
|
|
|
2011-11-21 10:32:09 -06:00
|
|
|
void XmlStream::moveToNextTag()
|
2011-11-18 11:09:43 -06:00
|
|
|
{
|
2011-11-21 10:32:09 -06:00
|
|
|
if( pos < tags.size())
|
|
|
|
++pos;
|
2011-11-18 11:09:43 -06:00
|
|
|
}
|
|
|
|
|
2011-11-24 06:19:57 -06:00
|
|
|
XmlStream::Tag XmlStream::ensureOpeningTag( int token )
|
|
|
|
{
|
2011-11-29 12:05:52 -06:00
|
|
|
return checkTag( OPENING( token ), false );
|
2011-11-24 06:19:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
XmlStream::Tag XmlStream::checkOpeningTag( int token )
|
|
|
|
{
|
2011-11-29 12:05:52 -06:00
|
|
|
return checkTag( OPENING( token ), true );
|
2011-11-24 06:19:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void XmlStream::ensureClosingTag( int token )
|
|
|
|
{
|
2011-11-29 12:05:52 -06:00
|
|
|
checkTag( CLOSING( token ), false );
|
2011-11-24 06:19:57 -06:00
|
|
|
}
|
|
|
|
|
2011-11-29 12:05:52 -06:00
|
|
|
XmlStream::Tag XmlStream::checkTag( int token, bool optional )
|
2011-11-24 06:19:57 -06:00
|
|
|
{
|
|
|
|
// either it's the following tag, or find it
|
|
|
|
int savedPos = pos;
|
2011-11-29 12:17:35 -06:00
|
|
|
if( optional )
|
|
|
|
{ // avoid printing debug messages about skipping tags if the optional one
|
|
|
|
// will not be found and the position will be reset back
|
2011-12-20 03:42:30 -06:00
|
|
|
if( currentToken() != token && !findTagInternal( token, true ))
|
2011-11-29 12:17:35 -06:00
|
|
|
{
|
|
|
|
pos = savedPos;
|
|
|
|
return Tag();
|
|
|
|
}
|
|
|
|
}
|
2011-12-20 03:42:30 -06:00
|
|
|
if( currentToken() == token || findTag( token ))
|
2011-11-24 06:19:57 -06:00
|
|
|
{
|
|
|
|
Tag ret = currentTag();
|
|
|
|
moveToNextTag();
|
|
|
|
return ret; // ok
|
|
|
|
}
|
|
|
|
if( optional )
|
|
|
|
{ // not a problem, just rewind
|
|
|
|
pos = savedPos;
|
|
|
|
return Tag();
|
|
|
|
}
|
2012-01-30 07:07:42 -06:00
|
|
|
SAL_WARN( "oox.xmlstream", "Expected tag " << tokenToString( token ) << " not found." );
|
2011-11-24 06:19:57 -06:00
|
|
|
return Tag();
|
|
|
|
}
|
|
|
|
|
2011-12-20 03:42:30 -06:00
|
|
|
bool XmlStream::findTag( int token )
|
2011-11-29 12:17:35 -06:00
|
|
|
{
|
2011-12-20 03:42:30 -06:00
|
|
|
return findTagInternal( token, false );
|
2011-11-29 12:17:35 -06:00
|
|
|
}
|
|
|
|
|
2012-01-30 07:07:42 -06:00
|
|
|
bool XmlStream::findTagInternal( int token, bool silent )
|
2011-11-24 06:19:57 -06:00
|
|
|
{
|
|
|
|
int depth = 0;
|
|
|
|
for(;
|
|
|
|
!atEnd();
|
|
|
|
moveToNextTag())
|
|
|
|
{
|
|
|
|
if( depth > 0 ) // we're inside a nested element, skip those
|
|
|
|
{
|
|
|
|
if( currentToken() == OPENING( currentToken()))
|
|
|
|
{
|
2012-01-30 07:07:42 -06:00
|
|
|
if( !silent )
|
|
|
|
SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
|
2011-11-24 06:19:57 -06:00
|
|
|
++depth;
|
|
|
|
}
|
|
|
|
else if( currentToken() == CLOSING( currentToken()))
|
2011-11-29 12:17:35 -06:00
|
|
|
{
|
2012-01-30 07:07:42 -06:00
|
|
|
if( !silent )
|
|
|
|
SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
|
2011-11-24 06:19:57 -06:00
|
|
|
--depth;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-01-30 07:07:42 -06:00
|
|
|
if( !silent )
|
|
|
|
SAL_WARN( "oox.xmlstream", "Malformed token " << currentToken() << " ("
|
|
|
|
<< tokenToString( currentToken()) << ")" );
|
2011-11-24 06:19:57 -06:00
|
|
|
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()))
|
|
|
|
{
|
2012-01-30 07:07:42 -06:00
|
|
|
if( !silent )
|
|
|
|
SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
|
2011-11-24 06:19:57 -06:00
|
|
|
++depth;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
abort();
|
|
|
|
}
|
2012-01-30 07:07:42 -06:00
|
|
|
if( !silent )
|
|
|
|
SAL_WARN( "oox.xmlstream", "Unexpected end of stream reached." );
|
2011-11-24 06:19:57 -06:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-01-30 07:07:42 -06:00
|
|
|
void XmlStream::skipElementInternal( int token, bool silent )
|
2011-11-24 06:19:57 -06:00
|
|
|
{
|
|
|
|
int closing = ( token & ~TAG_OPENING ) | TAG_CLOSING; // make it a closing tag
|
|
|
|
assert( currentToken() == OPENING( token ));
|
2012-01-30 07:07:42 -06:00
|
|
|
if( !silent )
|
|
|
|
SAL_INFO( "oox.xmlstream", "Skipping unexpected element " << tokenToString( currentToken()));
|
2011-11-24 10:31:42 -06:00
|
|
|
moveToNextTag();
|
|
|
|
// and just find the matching closing tag
|
2011-12-20 03:42:30 -06:00
|
|
|
if( findTag( closing ))
|
2011-11-24 06:19:57 -06:00
|
|
|
{
|
2012-01-30 07:07:42 -06:00
|
|
|
if( !silent )
|
|
|
|
SAL_INFO( "oox.xmlstream", "Skipped unexpected element " << tokenToString( token ));
|
2011-11-24 06:19:57 -06:00
|
|
|
moveToNextTag(); // and skip it too
|
|
|
|
return;
|
|
|
|
}
|
2011-11-29 12:54:54 -06:00
|
|
|
// this one is an unexpected problem, do not silent it
|
2012-01-30 07:07:42 -06:00
|
|
|
SAL_WARN( "oox.xmlstream", "Expected end of element " << tokenToString( token ) << " not found." );
|
2011-11-24 06:19:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void XmlStream::handleUnexpectedTag()
|
|
|
|
{
|
|
|
|
if( atEnd())
|
|
|
|
return;
|
|
|
|
if( currentToken() == CLOSING( currentToken()))
|
|
|
|
{
|
2012-01-30 07:07:42 -06:00
|
|
|
SAL_INFO( "oox.xmlstream", "Skipping unexpected tag " << tokenToString( currentToken()));
|
2011-11-24 06:19:57 -06:00
|
|
|
moveToNextTag(); // just skip it
|
|
|
|
return;
|
|
|
|
}
|
2011-11-29 12:54:54 -06:00
|
|
|
skipElementInternal( currentToken(), false ); // otherwise skip the entire element
|
2011-11-24 06:19:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-18 11:09:43 -06:00
|
|
|
void XmlStreamBuilder::appendOpeningTag( int token, const uno::Reference< xml::sax::XFastAttributeList >& attrs )
|
|
|
|
{
|
2011-11-21 10:32:09 -06:00
|
|
|
tags.push_back( Tag( OPENING( token ), attrs ));
|
2011-11-18 11:09:43 -06:00
|
|
|
}
|
|
|
|
|
2012-07-23 09:59:13 -05:00
|
|
|
void XmlStreamBuilder::appendOpeningTag( int token, const AttributeList& attrs )
|
|
|
|
{
|
|
|
|
tags.push_back( Tag( OPENING( token ), attrs ));
|
|
|
|
}
|
|
|
|
|
2011-11-18 11:09:43 -06:00
|
|
|
void XmlStreamBuilder::appendClosingTag( int token )
|
|
|
|
{
|
2011-11-21 10:32:09 -06:00
|
|
|
tags.push_back( Tag( CLOSING( token )));
|
2011-11-18 11:09:43 -06:00
|
|
|
}
|
|
|
|
|
2013-04-07 05:06:47 -05:00
|
|
|
void XmlStreamBuilder::appendCharacters( const OUString& chars )
|
2011-11-18 11:09:43 -06:00
|
|
|
{
|
2011-11-21 10:32:09 -06:00
|
|
|
assert( !tags.empty());
|
2011-12-01 08:22:28 -06:00
|
|
|
tags.back().text += chars;
|
2011-11-18 11:09:43 -06:00
|
|
|
}
|
|
|
|
|
2011-11-18 14:06:54 -06:00
|
|
|
} // namespace
|
2011-11-18 11:09:43 -06:00
|
|
|
} // namespace
|
|
|
|
|
2011-09-01 12:36:04 -05:00
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|