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"
15 #include <oox/token/namespacemap.hxx>
16 #include <oox/token/tokenmap.hxx>
17 #include <oox/token/tokens.hxx>
18 #include <oox/token/namespaces.hxx>
19 #include <rtl/ustring.hxx>
21 #define OPENING( token ) XML_STREAM_OPENING( token )
22 #define CLOSING( token ) XML_STREAM_CLOSING( token )
24 using namespace com::sun::star
;
29 namespace formulaimport
34 // a class that inherits from AttributeList, builds the internal data and then will be sliced off
35 // during conversion to the base class
36 class AttributeListBuilder
37 : public XmlStream::AttributeList
40 AttributeListBuilder( const uno::Reference
< xml::sax::XFastAttributeList
>& a
);
43 AttributeListBuilder::AttributeListBuilder( const uno::Reference
< xml::sax::XFastAttributeList
>& a
)
47 uno::Sequence
< xml::FastAttribute
> aFastAttrSeq
= a
->getFastAttributes();
48 const xml::FastAttribute
* pFastAttr
= aFastAttrSeq
.getConstArray();
49 sal_Int32 nFastAttrLength
= aFastAttrSeq
.getLength();
54 attrs
[ pFastAttr
[ i
].Token
] = pFastAttr
[ i
].Value
;
58 static OUString
tokenToString( int token
)
60 OUString tokenname
= StaticTokenMap::get().getUnicodeTokenName( token
& TOKEN_MASK
);
61 if( tokenname
.isEmpty())
63 int nmsp
= ( token
& NMSP_MASK
& ~( TAG_OPENING
| TAG_CLOSING
));
64 #if 0 // this is awfully long
65 OUString namespacename
= StaticNamespaceMap::get().count( nmsp
) != 0
66 ? StaticNamespaceMap::get()[ nmsp
] : OUString( "???" );
68 OUString namespacename
;
69 // only few are needed actually
83 if( token
== OPENING( token
))
84 return "<" + namespacename
+ ":" + tokenname
+ ">";
85 if( token
== CLOSING( token
))
86 return "</" + namespacename
+ ":" + tokenname
+ ">";
87 // just the name itself, not specified whether opening or closing
88 return namespacename
+ ":" + tokenname
;
93 OUString
& XmlStream::AttributeList::operator[] (int token
)
98 OUString
XmlStream::AttributeList::attribute( int token
, const OUString
& def
) const
100 std::map
< int, OUString
>::const_iterator find
= attrs
.find( token
);
101 if( find
!= attrs
.end())
106 bool XmlStream::AttributeList::attribute( int token
, bool def
) const
108 std::map
< int, OUString
>::const_iterator find
= attrs
.find( token
);
109 if( find
!= attrs
.end())
111 const OUString sValue
= find
->second
;
112 if( sValue
.equalsIgnoreAsciiCase("true") ||
113 sValue
.equalsIgnoreAsciiCase("on") ||
114 sValue
.equalsIgnoreAsciiCase("t") ||
115 sValue
.equalsIgnoreAsciiCase("1") )
117 if( sValue
.equalsIgnoreAsciiCase("false") ||
118 sValue
.equalsIgnoreAsciiCase("off") ||
119 sValue
.equalsIgnoreAsciiCase("f") ||
120 sValue
.equalsIgnoreAsciiCase("0") )
122 SAL_WARN( "oox.xmlstream", "Cannot convert \'" << sValue
<< "\' to bool." );
127 sal_Unicode
XmlStream::AttributeList::attribute( int token
, sal_Unicode def
) const
129 std::map
< int, OUString
>::const_iterator find
= attrs
.find( token
);
130 if( find
!= attrs
.end())
132 if( !find
->second
.isEmpty() )
134 if( find
->second
.getLength() != 1 )
135 SAL_WARN( "oox.xmlstream", "Cannot convert \'" << find
->second
<< "\' to sal_Unicode, stripping." );
136 return find
->second
[ 0 ];
142 XmlStream::Tag::Tag( int t
, const uno::Reference
< xml::sax::XFastAttributeList
>& a
, const OUString
& txt
)
144 , attributes( AttributeListBuilder( a
))
149 XmlStream::Tag::Tag( int t
, const AttributeList
& a
)
156 XmlStream::Tag::operator bool() const
158 return token
!= XML_TOKEN_INVALID
;
161 XmlStream::XmlStream()
164 // make sure our extra bit does not conflict with values used by oox
165 assert( TAG_OPENING
> ( 1024 << NMSP_SHIFT
));
168 bool XmlStream::atEnd() const
170 return pos
>= tags
.size();
173 XmlStream::Tag
XmlStream::currentTag() const
175 if( pos
>= tags
.size())
180 int XmlStream::currentToken() const
182 if( pos
>= tags
.size())
183 return XML_TOKEN_INVALID
;
184 return tags
[ pos
].token
;
187 void XmlStream::moveToNextTag()
189 if( pos
< tags
.size())
193 XmlStream::Tag
XmlStream::ensureOpeningTag( int token
)
195 return checkTag( OPENING( token
), false );
198 XmlStream::Tag
XmlStream::checkOpeningTag( int token
)
200 return checkTag( OPENING( token
), true );
203 void XmlStream::ensureClosingTag( int token
)
205 checkTag( CLOSING( token
), false );
208 XmlStream::Tag
XmlStream::checkTag( int token
, bool optional
)
210 // either it's the following tag, or find it
213 { // avoid printing debug messages about skipping tags if the optional one
214 // will not be found and the position will be reset back
215 if( currentToken() != token
&& !findTagInternal( token
, true ))
221 if( currentToken() == token
|| findTag( token
))
223 Tag ret
= currentTag();
228 { // not a problem, just rewind
232 SAL_WARN( "oox.xmlstream", "Expected tag " << tokenToString( token
) << " not found." );
236 bool XmlStream::findTag( int token
)
238 return findTagInternal( token
, false );
241 bool XmlStream::findTagInternal( int token
, bool silent
)
248 if( depth
> 0 ) // we're inside a nested element, skip those
250 if( currentToken() == OPENING( currentToken()))
253 SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
256 else if( currentToken() == CLOSING( currentToken()))
259 SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
265 SAL_WARN( "oox.xmlstream", "Malformed token " << currentToken() << " ("
266 << tokenToString( currentToken()) << ")" );
271 if( currentToken() == token
)
272 return true; // ok, found
273 if( currentToken() == CLOSING( currentToken()))
274 return false; // that would be leaving current element, so not found
275 if( currentToken() == OPENING( currentToken()))
278 SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
285 SAL_WARN( "oox.xmlstream", "Unexpected end of stream reached." );
289 void XmlStream::skipElementInternal( int token
, bool silent
)
291 int closing
= ( token
& ~TAG_OPENING
) | TAG_CLOSING
; // make it a closing tag
292 assert( currentToken() == OPENING( token
));
294 SAL_INFO( "oox.xmlstream", "Skipping unexpected element " << tokenToString( currentToken()));
296 // and just find the matching closing tag
297 if( findTag( closing
))
300 SAL_INFO( "oox.xmlstream", "Skipped unexpected element " << tokenToString( token
));
301 moveToNextTag(); // and skip it too
304 // this one is an unexpected problem, do not silent it
305 SAL_WARN( "oox.xmlstream", "Expected end of element " << tokenToString( token
) << " not found." );
308 void XmlStream::handleUnexpectedTag()
312 if( currentToken() == CLOSING( currentToken()))
314 SAL_INFO( "oox.xmlstream", "Skipping unexpected tag " << tokenToString( currentToken()));
315 moveToNextTag(); // just skip it
318 skipElementInternal( currentToken(), false ); // otherwise skip the entire element
322 void XmlStreamBuilder::appendOpeningTag( int token
, const uno::Reference
< xml::sax::XFastAttributeList
>& attrs
)
324 tags
.push_back( Tag( OPENING( token
), attrs
));
327 void XmlStreamBuilder::appendOpeningTag( int token
, const AttributeList
& attrs
)
329 tags
.push_back( Tag( OPENING( token
), attrs
));
332 void XmlStreamBuilder::appendClosingTag( int token
)
334 tags
.push_back( Tag( CLOSING( token
)));
337 void XmlStreamBuilder::appendCharacters( const OUString
& chars
)
339 assert( !tags
.empty());
340 tags
.back().text
+= chars
;
346 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */