Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / oox / source / mathml / importutils.cxx
blob178a3eed6791cc4243c526a2d9e2a9b06a5d058e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <oox/mathml/importutils.hxx>
12 #include <assert.h>
14 #include <com/sun/star/xml/FastAttribute.hpp>
15 #include <com/sun/star/xml/sax/XFastAttributeList.hpp>
16 #include <oox/token/namespacemap.hxx>
17 #include <oox/token/tokenmap.hxx>
18 #include <oox/token/tokens.hxx>
19 #include <oox/token/namespaces.hxx>
20 #include <rtl/ustring.hxx>
21 #include <sal/log.hxx>
23 #define OPENING( token ) XML_STREAM_OPENING( token )
24 #define CLOSING( token ) XML_STREAM_CLOSING( token )
26 using namespace com::sun::star;
28 namespace oox
31 namespace formulaimport
34 namespace
36 // a class that inherits from AttributeList, builds the internal data and then will be sliced off
37 // during conversion to the base class
38 class AttributeListBuilder
39 : public XmlStream::AttributeList
41 public:
42 explicit AttributeListBuilder( const uno::Reference< xml::sax::XFastAttributeList >& a );
45 AttributeListBuilder::AttributeListBuilder( const uno::Reference< xml::sax::XFastAttributeList >& a )
47 if( a.get() == nullptr )
48 return;
49 const uno::Sequence< xml::FastAttribute > aFastAttrSeq = a->getFastAttributes();
50 for( const xml::FastAttribute& rFastAttr : aFastAttrSeq )
52 attrs[ rFastAttr.Token ] = rFastAttr.Value;
56 OString tokenToString( int token )
58 uno::Sequence< sal_Int8 > const & aTokenNameSeq = StaticTokenMap::get().getUtf8TokenName( token & TOKEN_MASK );
59 OString tokenname( reinterpret_cast< const char* >( aTokenNameSeq.getConstArray() ), aTokenNameSeq.getLength() );
60 if( tokenname.isEmpty())
61 tokenname = "???";
62 int nmsp = ( token & NMSP_MASK & ~( TAG_OPENING | TAG_CLOSING ));
63 #if 0 // this is awfully long
64 OString namespacename = StaticNamespaceMap::get().count( nmsp ) != 0
65 ? StaticNamespaceMap::get()[ nmsp ] : OString( "???" );
66 #else
67 OString namespacename;
68 // only few are needed actually
69 switch( nmsp )
71 case NMSP_officeMath:
72 namespacename = "m";
73 break;
74 case NMSP_doc:
75 namespacename = "w";
76 break;
77 default:
78 namespacename = "?";
79 break;
81 #endif
82 if( token == OPENING( token ))
83 return "<" + namespacename + ":" + tokenname + ">";
84 if( token == CLOSING( token ))
85 return "</" + namespacename + ":" + tokenname + ">";
86 // just the name itself, not specified whether opening or closing
87 return namespacename + ":" + tokenname;
90 } // namespace
92 OUString& XmlStream::AttributeList::operator[] (int token)
94 return attrs[token];
97 OUString XmlStream::AttributeList::attribute( int token, const OUString& def ) const
99 std::map< int, OUString >::const_iterator find = attrs.find( token );
100 if( find != attrs.end())
101 return find->second;
102 return def;
105 bool XmlStream::AttributeList::attribute( int token, bool def ) const
107 std::map< int, OUString >::const_iterator find = attrs.find( token );
108 if( find != attrs.end())
110 const OUString sValue = find->second;
111 if( sValue.equalsIgnoreAsciiCase("true") ||
112 sValue.equalsIgnoreAsciiCase("on") ||
113 sValue.equalsIgnoreAsciiCase("t") ||
114 sValue.equalsIgnoreAsciiCase("1") )
115 return true;
116 if( sValue.equalsIgnoreAsciiCase("false") ||
117 sValue.equalsIgnoreAsciiCase("off") ||
118 sValue.equalsIgnoreAsciiCase("f") ||
119 sValue.equalsIgnoreAsciiCase("0") )
120 return false;
121 SAL_WARN( "oox.xmlstream", "Cannot convert \'" << sValue << "\' to bool." );
123 return def;
126 sal_Unicode XmlStream::AttributeList::attribute( int token, sal_Unicode def ) const
128 std::map< int, OUString >::const_iterator find = attrs.find( token );
129 if( find != attrs.end())
131 if( !find->second.isEmpty() )
133 if( find->second.getLength() != 1 )
134 SAL_WARN( "oox.xmlstream", "Cannot convert \'" << find->second << "\' to sal_Unicode, stripping." );
135 return find->second[ 0 ];
138 return def;
141 XmlStream::Tag::Tag( int t, const uno::Reference< xml::sax::XFastAttributeList >& a )
142 : token( t )
143 , attributes( AttributeListBuilder( a ))
147 XmlStream::Tag::Tag( int t, const AttributeList& a )
148 : token( t )
149 , attributes( a )
153 XmlStream::Tag::operator bool() const
155 return token != XML_TOKEN_INVALID;
158 XmlStream::XmlStream()
159 : pos( 0 )
161 // make sure our extra bit does not conflict with values used by oox
162 assert( TAG_OPENING > ( 1024 << NMSP_SHIFT ));
165 bool XmlStream::atEnd() const
167 return pos >= tags.size();
170 XmlStream::Tag XmlStream::currentTag() const
172 if( pos >= tags.size())
173 return Tag();
174 return tags[ pos ];
177 int XmlStream::currentToken() const
179 if( pos >= tags.size())
180 return XML_TOKEN_INVALID;
181 return tags[ pos ].token;
184 void XmlStream::moveToNextTag()
186 if( pos < tags.size())
187 ++pos;
190 XmlStream::Tag XmlStream::ensureOpeningTag( int token )
192 return checkTag( OPENING( token ), false );
195 XmlStream::Tag XmlStream::checkOpeningTag( int token )
197 return checkTag( OPENING( token ), true );
200 void XmlStream::ensureClosingTag( int token )
202 checkTag( CLOSING( token ), false );
205 XmlStream::Tag XmlStream::checkTag( int token, bool optional )
207 // either it's the following tag, or find it
208 int savedPos = pos;
209 if( optional )
210 { // avoid printing debug messages about skipping tags if the optional one
211 // will not be found and the position will be reset back
212 if( currentToken() != token && !findTagInternal( token, true ))
214 pos = savedPos;
215 return Tag();
218 if( currentToken() == token || findTag( token ))
220 Tag ret = currentTag();
221 moveToNextTag();
222 return ret; // ok
224 if( optional )
225 { // not a problem, just rewind
226 pos = savedPos;
227 return Tag();
229 SAL_WARN( "oox.xmlstream", "Expected tag " << tokenToString( token ) << " not found." );
230 return Tag();
233 bool XmlStream::findTag( int token )
235 return findTagInternal( token, false );
238 bool XmlStream::findTagInternal( int token, bool silent )
240 int depth = 0;
241 for(;
242 !atEnd();
243 moveToNextTag())
245 if( depth > 0 ) // we're inside a nested element, skip those
247 if( currentToken() == OPENING( currentToken()))
249 if( !silent )
250 SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
251 ++depth;
253 else if( currentToken() == CLOSING( currentToken()))
255 if( !silent )
256 SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
257 --depth;
259 else
261 if( !silent )
262 SAL_WARN( "oox.xmlstream", "Malformed token " << currentToken() << " ("
263 << tokenToString( currentToken()) << ")" );
264 abort();
266 continue;
268 if( currentToken() == token )
269 return true; // ok, found
270 if( currentToken() == CLOSING( currentToken()))
271 return false; // that would be leaving current element, so not found
272 if( currentToken() == OPENING( currentToken()))
274 if( !silent )
275 SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
276 ++depth;
278 else
279 abort();
281 if( !silent )
282 SAL_WARN( "oox.xmlstream", "Unexpected end of stream reached." );
283 return false;
286 void XmlStream::skipElementInternal( int token, bool silent )
288 int closing = ( token & ~TAG_OPENING ) | TAG_CLOSING; // make it a closing tag
289 assert( currentToken() == OPENING( token ));
290 if( !silent )
291 SAL_INFO( "oox.xmlstream", "Skipping unexpected element " << tokenToString( currentToken()));
292 moveToNextTag();
293 // and just find the matching closing tag
294 if( findTag( closing ))
296 if( !silent )
297 SAL_INFO( "oox.xmlstream", "Skipped unexpected element " << tokenToString( token ));
298 moveToNextTag(); // and skip it too
299 return;
301 // this one is an unexpected problem, do not silent it
302 SAL_WARN( "oox.xmlstream", "Expected end of element " << tokenToString( token ) << " not found." );
305 void XmlStream::handleUnexpectedTag()
307 if( atEnd())
308 return;
309 if( currentToken() == CLOSING( currentToken()))
311 SAL_INFO( "oox.xmlstream", "Skipping unexpected tag " << tokenToString( currentToken()));
312 moveToNextTag(); // just skip it
313 return;
315 skipElementInternal( currentToken(), false ); // otherwise skip the entire element
318 void XmlStreamBuilder::appendOpeningTag( int token, const uno::Reference< xml::sax::XFastAttributeList >& attrs )
320 tags.emplace_back( OPENING( token ), attrs );
323 void XmlStreamBuilder::appendOpeningTag( int token, const AttributeList& attrs )
325 tags.emplace_back( OPENING( token ), attrs );
328 void XmlStreamBuilder::appendClosingTag( int token )
330 tags.emplace_back( CLOSING( token ));
333 void XmlStreamBuilder::appendCharacters( const OUString& chars )
335 assert( !tags.empty());
336 tags.back().text += chars;
339 } // namespace
340 } // namespace
342 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */