1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
10 #include <oox/mathml/importutils.hxx>
14 #include <com/sun/star/xml/FastAttribute.hpp>
15 #include <com/sun/star/xml/sax/XFastAttributeList.hpp>
16 #include <oox/token/tokenmap.hxx>
17 #include <oox/token/tokens.hxx>
18 #include <oox/token/namespaces.hxx>
19 #include <rtl/ustring.hxx>
20 #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::formulaimport
33 // a class that inherits from AttributeList, builds the internal data and then will be sliced off
34 // during conversion to the base class
35 class AttributeListBuilder
36 : public XmlStream::AttributeList
39 explicit AttributeListBuilder( const uno::Reference
< xml::sax::XFastAttributeList
>& a
);
42 AttributeListBuilder::AttributeListBuilder( const uno::Reference
< xml::sax::XFastAttributeList
>& a
)
46 const uno::Sequence
< xml::FastAttribute
> aFastAttrSeq
= a
->getFastAttributes();
47 for( const xml::FastAttribute
& rFastAttr
: aFastAttrSeq
)
49 attrs
[ rFastAttr
.Token
] = rFastAttr
.Value
;
53 OString
tokenToString( int token
)
55 uno::Sequence
<sal_Int8
> const& aTokenNameSeq
= TokenMap::getUtf8TokenName(token
& TOKEN_MASK
);
56 OString
tokenname( reinterpret_cast< const char* >( aTokenNameSeq
.getConstArray() ), aTokenNameSeq
.getLength() );
57 if( tokenname
.isEmpty())
58 tokenname
= "???"_ostr
;
59 int nmsp
= ( token
& NMSP_MASK
& ~( TAG_OPENING
| TAG_CLOSING
));
60 #if 0 // this is awfully long
61 OString namespacename
= StaticNamespaceMap::get().count( nmsp
) != 0
62 ? StaticNamespaceMap::get()[ nmsp
] : OString( "???" );
64 OString namespacename
;
65 // only few are needed actually
69 namespacename
= "m"_ostr
;
72 namespacename
= "w"_ostr
;
75 namespacename
= "?"_ostr
;
79 if( token
== OPENING( token
))
80 return "<" + namespacename
+ ":" + tokenname
+ ">";
81 if( token
== CLOSING( token
))
82 return "</" + namespacename
+ ":" + tokenname
+ ">";
83 // just the name itself, not specified whether opening or closing
84 return namespacename
+ ":" + tokenname
;
89 OUString
& XmlStream::AttributeList::operator[] (int token
)
94 OUString
XmlStream::AttributeList::attribute( int token
, const OUString
& def
) const
96 std::map
< int, OUString
>::const_iterator find
= attrs
.find( token
);
97 if( find
!= attrs
.end())
102 bool XmlStream::AttributeList::attribute( int token
, bool def
) const
104 std::map
< int, OUString
>::const_iterator find
= attrs
.find( token
);
105 if( find
!= attrs
.end())
107 const OUString sValue
= find
->second
;
108 if( sValue
.equalsIgnoreAsciiCase("true") ||
109 sValue
.equalsIgnoreAsciiCase("on") ||
110 sValue
.equalsIgnoreAsciiCase("t") ||
111 sValue
.equalsIgnoreAsciiCase("1") )
113 if( sValue
.equalsIgnoreAsciiCase("false") ||
114 sValue
.equalsIgnoreAsciiCase("off") ||
115 sValue
.equalsIgnoreAsciiCase("f") ||
116 sValue
.equalsIgnoreAsciiCase("0") )
118 SAL_WARN( "oox.xmlstream", "Cannot convert \'" << sValue
<< "\' to bool." );
123 sal_Unicode
XmlStream::AttributeList::attribute( int token
, sal_Unicode def
) const
125 std::map
< int, OUString
>::const_iterator find
= attrs
.find( token
);
126 if( find
!= attrs
.end())
128 if( !find
->second
.isEmpty() )
130 if( find
->second
.getLength() != 1 )
131 SAL_WARN( "oox.xmlstream", "Cannot convert \'" << find
->second
<< "\' to sal_Unicode, stripping." );
132 return find
->second
[ 0 ];
138 XmlStream::Tag::Tag( int t
, const uno::Reference
< xml::sax::XFastAttributeList
>& a
)
140 , attributes( AttributeListBuilder( a
))
144 XmlStream::Tag::Tag( int t
, AttributeList a
)
146 , attributes(std::move( a
))
150 XmlStream::Tag::operator bool() const
152 return token
!= XML_TOKEN_INVALID
;
155 XmlStream::XmlStream()
158 // make sure our extra bit does not conflict with values used by oox
159 assert( TAG_OPENING
> ( 1024 << NMSP_SHIFT
));
162 bool XmlStream::atEnd() const
164 return pos
>= tags
.size();
167 XmlStream::Tag
XmlStream::currentTag() const
169 if( pos
>= tags
.size())
174 int XmlStream::currentToken() const
176 if( pos
>= tags
.size())
177 return XML_TOKEN_INVALID
;
178 return tags
[ pos
].token
;
181 void XmlStream::moveToNextTag()
183 if( pos
< tags
.size())
187 XmlStream::Tag
XmlStream::ensureOpeningTag( int token
)
189 return checkTag( OPENING( token
), false );
192 XmlStream::Tag
XmlStream::checkOpeningTag( int token
)
194 return checkTag( OPENING( token
), true );
197 void XmlStream::ensureClosingTag( int token
)
199 checkTag( CLOSING( token
), false );
202 XmlStream::Tag
XmlStream::checkTag( int token
, bool optional
)
204 // either it's the following tag, or find it
207 { // avoid printing debug messages about skipping tags if the optional one
208 // will not be found and the position will be reset back
209 if( currentToken() != token
&& !findTagInternal( token
, true ))
215 if( currentToken() == token
|| findTag( token
))
217 Tag ret
= currentTag();
222 { // not a problem, just rewind
226 SAL_WARN( "oox.xmlstream", "Expected tag " << tokenToString( token
) << " not found." );
230 bool XmlStream::findTag( int token
)
232 return findTagInternal( token
, false );
235 bool XmlStream::findTagInternal( int token
, bool silent
)
242 if( depth
> 0 ) // we're inside a nested element, skip those
244 if( currentToken() == OPENING( currentToken()))
247 SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
250 else if( currentToken() == CLOSING( currentToken()))
253 SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
259 SAL_WARN( "oox.xmlstream", "Malformed token " << currentToken() << " ("
260 << tokenToString( currentToken()) << ")" );
265 if( currentToken() == token
)
266 return true; // ok, found
267 if( currentToken() == CLOSING( currentToken()))
268 return false; // that would be leaving current element, so not found
269 if( currentToken() == OPENING( currentToken()))
272 SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
279 SAL_WARN( "oox.xmlstream", "Unexpected end of stream reached." );
283 void XmlStream::skipElementInternal( int token
, bool silent
)
285 int closing
= ( token
& ~TAG_OPENING
) | TAG_CLOSING
; // make it a closing tag
286 assert( currentToken() == OPENING( token
));
288 SAL_INFO( "oox.xmlstream", "Skipping unexpected element " << tokenToString( currentToken()));
290 // and just find the matching closing tag
291 if( findTag( closing
))
294 SAL_INFO( "oox.xmlstream", "Skipped unexpected element " << tokenToString( token
));
295 moveToNextTag(); // and skip it too
298 // this one is an unexpected problem, do not silent it
299 SAL_WARN( "oox.xmlstream", "Expected end of element " << tokenToString( token
) << " not found." );
302 void XmlStream::handleUnexpectedTag()
306 if( currentToken() == CLOSING( currentToken()))
308 SAL_INFO( "oox.xmlstream", "Skipping unexpected tag " << tokenToString( currentToken()));
309 moveToNextTag(); // just skip it
312 skipElementInternal( currentToken(), false ); // otherwise skip the entire element
315 void XmlStreamBuilder::appendOpeningTag( int token
, const uno::Reference
< xml::sax::XFastAttributeList
>& attrs
)
317 tags
.emplace_back( OPENING( token
), attrs
);
320 void XmlStreamBuilder::appendOpeningTag( int token
, const AttributeList
& attrs
)
322 tags
.emplace_back( OPENING( token
), attrs
);
325 void XmlStreamBuilder::appendClosingTag( int token
)
327 tags
.emplace_back( CLOSING( token
));
330 void XmlStreamBuilder::appendCharacters( std::u16string_view chars
)
332 assert( !tags
.empty());
333 tags
.back().text
+= chars
;
338 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */