Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * Version: MPL 1.1 / GPLv3+ / LGPLv3+
4 : : *
5 : : * The contents of this file are subject to the Mozilla Public License Version
6 : : * 1.1 (the "License"); you may not use this file except in compliance with
7 : : * the License or as specified alternatively below. You may obtain a copy of
8 : : * the License at http://www.mozilla.org/MPL/
9 : : *
10 : : * Software distributed under the License is distributed on an "AS IS" basis,
11 : : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : : * for the specific language governing rights and limitations under the
13 : : * License.
14 : : *
15 : : * Major Contributor(s):
16 : : * Copyright (C) 2011 Tor Lillqvist <tlillqvist@suse.com> (initial developer)
17 : : *
18 : : * All Rights Reserved.
19 : : *
20 : : * For minor contributions see the git repository.
21 : : *
22 : : * Alternatively, the contents of this file may be used under the terms of
23 : : * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
24 : : * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
25 : : * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
26 : : * instead of those above.
27 : : */
28 : :
29 : : #include "oox/mathml/importutils.hxx"
30 : :
31 : : #include <assert.h>
32 : : #include <stdio.h>
33 : :
34 : : #include <oox/token/namespacemap.hxx>
35 : : #include <oox/token/tokenmap.hxx>
36 : : #include <oox/token/tokens.hxx>
37 : : #include <oox/token/namespaces.hxx>
38 : : #include <rtl/oustringostreaminserter.hxx>
39 : : #include <rtl/string.hxx>
40 : :
41 : : // *sigh*
42 : : #define STR( str ) OUString( RTL_CONSTASCII_USTRINGPARAM( str ))
43 : :
44 : : #define OPENING( token ) XML_STREAM_OPENING( token )
45 : : #define CLOSING( token ) XML_STREAM_CLOSING( token )
46 : :
47 : : using namespace com::sun::star;
48 : : using rtl::OUString;
49 : :
50 : : namespace oox
51 : : {
52 : :
53 : : namespace formulaimport
54 : : {
55 : :
56 : : namespace
57 : : {
58 : : // a class that inherits from AttributeList, builds the internal data and then will be sliced off
59 : : // during conversion to the base class
60 : 28824 : class AttributeListBuilder
61 : : : public XmlStream::AttributeList
62 : : {
63 : : public:
64 : : AttributeListBuilder( const uno::Reference< xml::sax::XFastAttributeList >& a );
65 : : };
66 : :
67 : 28824 : AttributeListBuilder::AttributeListBuilder( const uno::Reference< xml::sax::XFastAttributeList >& a )
68 : : {
69 [ + + ][ + - ]: 28824 : if( a.get() == NULL )
70 : 28824 : return;
71 [ + - ][ + - ]: 7059 : uno::Sequence< xml::FastAttribute > aFastAttrSeq = a->getFastAttributes();
72 : 7059 : const xml::FastAttribute* pFastAttr = aFastAttrSeq.getConstArray();
73 : 7059 : sal_Int32 nFastAttrLength = aFastAttrSeq.getLength();
74 [ + + ]: 10548 : for( int i = 0;
75 : : i < nFastAttrLength;
76 : : ++i )
77 : : {
78 [ + - ]: 3489 : attrs[ pFastAttr[ i ].Token ] = pFastAttr[ i ].Value;
79 [ + - ]: 28824 : }
80 : : }
81 : :
82 : 0 : static OUString tokenToString( int token )
83 : : {
84 [ # # ][ # # ]: 0 : OUString tokenname = StaticTokenMap::get().getUnicodeTokenName( token & TOKEN_MASK );
85 [ # # ]: 0 : if( tokenname.isEmpty())
86 [ # # ]: 0 : tokenname = STR( "???" );
87 : 0 : int nmsp = ( token & NMSP_MASK & ~( TAG_OPENING | TAG_CLOSING ));
88 : : #if 0 // this is awfully long
89 : : OUString namespacename = StaticNamespaceMap::get().count( nmsp ) != 0
90 : : ? StaticNamespaceMap::get()[ nmsp ] : STR( "???" );
91 : : #else
92 : 0 : OUString namespacename;
93 : : // only few are needed actually
94 [ # # # ]: 0 : switch( nmsp )
95 : : {
96 : : case NMSP_officeMath:
97 [ # # ]: 0 : namespacename = STR( "m" );
98 : 0 : break;
99 : : case NMSP_doc:
100 [ # # ]: 0 : namespacename = STR( "w" );
101 : 0 : break;
102 : : default:
103 [ # # ]: 0 : namespacename = STR( "?" );
104 : 0 : break;
105 : : }
106 : : #endif
107 [ # # ]: 0 : if( token == OPENING( token ))
108 [ # # ][ # # ]: 0 : return STR( "<" ) + namespacename + STR( ":" ) + tokenname + STR ( ">" );
[ # # ]
109 [ # # ]: 0 : if( token == CLOSING( token ))
110 [ # # ][ # # ]: 0 : return STR( "</" ) + namespacename + STR( ":" ) + tokenname + STR ( ">" );
[ # # ]
111 : : // just the name itself, not specified whether opening or closing
112 [ # # ]: 0 : return namespacename + STR( ":" ) + tokenname;
113 : : }
114 : :
115 : : } // namespace
116 : :
117 : 390 : OUString& XmlStream::AttributeList::operator[] (int token)
118 : : {
119 : 390 : return attrs[token];
120 : : }
121 : :
122 : 3342 : rtl::OUString XmlStream::AttributeList::attribute( int token, const rtl::OUString& def ) const
123 : : {
124 [ + - ]: 3342 : std::map< int, rtl::OUString >::const_iterator find = attrs.find( token );
125 [ + + ]: 3342 : if( find != attrs.end())
126 : 1542 : return find->second;
127 : 3342 : return def;
128 : : }
129 : :
130 : 60 : bool XmlStream::AttributeList::attribute( int token, bool def ) const
131 : : {
132 [ + - ]: 60 : std::map< int, rtl::OUString >::const_iterator find = attrs.find( token );
133 [ + - ]: 60 : if( find != attrs.end())
134 : : {
135 : 60 : const rtl::OUString sValue = find->second;
136 [ + - ][ + - : 204 : if( sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("true")) ||
+ + + - +
- ]
137 : 60 : sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("on")) ||
138 : 42 : sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("t")) ||
139 : 42 : sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("1")) )
140 : 60 : return true;
141 [ # # # # : 0 : if( sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("false")) ||
# # # # ]
[ # # ]
142 : 0 : sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("off")) ||
143 : 0 : sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("f")) ||
144 : 0 : sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("0")) )
145 : 0 : return false;
146 [ - + ]: 60 : SAL_WARN( "oox.xmlstream", "Cannot convert \'" << sValue << "\' to bool." );
147 : : }
148 : 60 : return def;
149 : : }
150 : :
151 : 234 : sal_Unicode XmlStream::AttributeList::attribute( int token, sal_Unicode def ) const
152 : : {
153 [ + - ]: 234 : std::map< int, rtl::OUString >::const_iterator find = attrs.find( token );
154 [ + - ]: 234 : if( find != attrs.end())
155 : : {
156 [ + - ]: 234 : if( !find->second.isEmpty() )
157 : : {
158 : 234 : if( find->second.getLength() != 1 )
159 : : SAL_WARN( "oox.xmlstream", "Cannot convert \'" << find->second << "\' to sal_Unicode, stripping." );
160 : 234 : return find->second[ 0 ];
161 : : }
162 : : }
163 : 234 : return def;
164 : : }
165 : :
166 : 28824 : XmlStream::Tag::Tag( int t, const uno::Reference< xml::sax::XFastAttributeList >& a, const rtl::OUString& txt )
167 : : : token( t )
168 : : , attributes( AttributeListBuilder( a ))
169 : 28824 : , text( txt )
170 : : {
171 : 28824 : }
172 : :
173 : 390 : XmlStream::Tag::Tag( int t, const AttributeList& a )
174 : : : token( t )
175 : 390 : , attributes( a )
176 : : {
177 : 390 : }
178 : :
179 : :
180 : 4923 : XmlStream::Tag::operator bool() const
181 : : {
182 : 4923 : return token != XML_TOKEN_INVALID;
183 : : }
184 : :
185 : 765 : XmlStream::XmlStream()
186 : 765 : : pos( 0 )
187 : : {
188 : : // make sure our extra bit does not conflict with values used by oox
189 : : assert( TAG_OPENING > ( 1024 << NMSP_SHIFT ));
190 : 765 : }
191 : :
192 : 29667 : bool XmlStream::atEnd() const
193 : : {
194 : 29667 : return pos >= tags.size();
195 : : }
196 : :
197 : 22848 : XmlStream::Tag XmlStream::currentTag() const
198 : : {
199 [ - + ]: 22848 : if( pos >= tags.size())
200 [ # # ]: 0 : return Tag();
201 : 22848 : return tags[ pos ];
202 : : }
203 : :
204 : 118917 : int XmlStream::currentToken() const
205 : : {
206 [ - + ]: 118917 : if( pos >= tags.size())
207 : 0 : return XML_TOKEN_INVALID;
208 : 118917 : return tags[ pos ].token;
209 : : }
210 : :
211 : 34524 : void XmlStream::moveToNextTag()
212 : : {
213 [ + - ]: 34524 : if( pos < tags.size())
214 : 34524 : ++pos;
215 : 34524 : }
216 : :
217 : 9486 : XmlStream::Tag XmlStream::ensureOpeningTag( int token )
218 : : {
219 : 9486 : return checkTag( OPENING( token ), false );
220 : : }
221 : :
222 : 4923 : XmlStream::Tag XmlStream::checkOpeningTag( int token )
223 : : {
224 : 4923 : return checkTag( OPENING( token ), true );
225 : : }
226 : :
227 : 11424 : void XmlStream::ensureClosingTag( int token )
228 : : {
229 : 11424 : checkTag( CLOSING( token ), false );
230 : 11424 : }
231 : :
232 : 25833 : XmlStream::Tag XmlStream::checkTag( int token, bool optional )
233 : : {
234 : : // either it's the following tag, or find it
235 : 25833 : int savedPos = pos;
236 [ + + ]: 25833 : if( optional )
237 : : { // avoid printing debug messages about skipping tags if the optional one
238 : : // will not be found and the position will be reset back
239 [ + + ][ + + ]: 4923 : if( currentToken() != token && !findTagInternal( token, true ))
[ + + ]
240 : : {
241 : 2985 : pos = savedPos;
242 [ + - ]: 2985 : return Tag();
243 : : }
244 : : }
245 [ + + ][ + - ]: 22848 : if( currentToken() == token || findTag( token ))
[ + - ]
246 : : {
247 [ + - ]: 22848 : Tag ret = currentTag();
248 [ + - ]: 22848 : moveToNextTag();
249 [ + - ][ + - ]: 22848 : return ret; // ok
250 : : }
251 [ # # ]: 0 : if( optional )
252 : : { // not a problem, just rewind
253 : 0 : pos = savedPos;
254 [ # # ]: 0 : return Tag();
255 : : }
256 : : SAL_WARN( "oox.xmlstream", "Expected tag " << tokenToString( token ) << " not found." );
257 [ # # ]: 25833 : return Tag();
258 : : }
259 : :
260 : 1695 : bool XmlStream::findTag( int token )
261 : : {
262 : 1695 : return findTagInternal( token, false );
263 : : }
264 : :
265 : 4737 : bool XmlStream::findTagInternal( int token, bool silent )
266 : : {
267 : 4737 : int depth = 0;
268 [ + - ]: 21150 : for(;
269 : 16413 : !atEnd();
270 : 11676 : moveToNextTag())
271 : : {
272 [ + + ]: 16413 : if( depth > 0 ) // we're inside a nested element, skip those
273 : : {
274 [ + + ]: 7497 : if( currentToken() == OPENING( currentToken()))
275 : : {
276 : 1659 : if( !silent )
277 : : SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
278 : 1659 : ++depth;
279 : : }
280 [ + - ]: 5838 : else if( currentToken() == CLOSING( currentToken()))
281 : : {
282 : 5838 : if( !silent )
283 : : SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
284 : 5838 : --depth;
285 : : }
286 : : else
287 : : {
288 : 0 : if( !silent )
289 : : SAL_WARN( "oox.xmlstream", "Malformed token " << currentToken() << " ("
290 : : << tokenToString( currentToken()) << ")" );
291 : 0 : abort();
292 : : }
293 : 7497 : continue;
294 : : }
295 [ + + ]: 8916 : if( currentToken() == token )
296 : 1425 : return true; // ok, found
297 [ + + ]: 7491 : if( currentToken() == CLOSING( currentToken()))
298 : 3312 : return false; // that would be leaving current element, so not found
299 [ + - ]: 4179 : if( currentToken() == OPENING( currentToken()))
300 : : {
301 : 4179 : if( !silent )
302 : : SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
303 : 4179 : ++depth;
304 : : }
305 : : else
306 : 0 : abort();
307 : : }
308 : 0 : if( !silent )
309 : : SAL_WARN( "oox.xmlstream", "Unexpected end of stream reached." );
310 : 4737 : return false;
311 : : }
312 : :
313 : 0 : void XmlStream::skipElementInternal( int token, bool silent )
314 : : {
315 : 0 : int closing = ( token & ~TAG_OPENING ) | TAG_CLOSING; // make it a closing tag
316 : : assert( currentToken() == OPENING( token ));
317 : 0 : if( !silent )
318 : : SAL_INFO( "oox.xmlstream", "Skipping unexpected element " << tokenToString( currentToken()));
319 : 0 : moveToNextTag();
320 : : // and just find the matching closing tag
321 [ # # ]: 0 : if( findTag( closing ))
322 : : {
323 : 0 : if( !silent )
324 : : SAL_INFO( "oox.xmlstream", "Skipped unexpected element " << tokenToString( token ));
325 : 0 : moveToNextTag(); // and skip it too
326 : 0 : return;
327 : : }
328 : : // this one is an unexpected problem, do not silent it
329 : : SAL_WARN( "oox.xmlstream", "Expected end of element " << tokenToString( token ) << " not found." );
330 : : }
331 : :
332 : 0 : void XmlStream::handleUnexpectedTag()
333 : : {
334 [ # # ]: 0 : if( atEnd())
335 : 0 : return;
336 [ # # ]: 0 : if( currentToken() == CLOSING( currentToken()))
337 : : {
338 : : SAL_INFO( "oox.xmlstream", "Skipping unexpected tag " << tokenToString( currentToken()));
339 : 0 : moveToNextTag(); // just skip it
340 : 0 : return;
341 : : }
342 : 0 : skipElementInternal( currentToken(), false ); // otherwise skip the entire element
343 : : }
344 : :
345 : :
346 : 12729 : void XmlStreamBuilder::appendOpeningTag( int token, const uno::Reference< xml::sax::XFastAttributeList >& attrs )
347 : : {
348 [ + - ][ + - ]: 12729 : tags.push_back( Tag( OPENING( token ), attrs ));
[ + - ]
349 : 12729 : }
350 : :
351 : 390 : void XmlStreamBuilder::appendOpeningTag( int token, const AttributeList& attrs )
352 : : {
353 [ + - ]: 390 : tags.push_back( Tag( OPENING( token ), attrs ));
354 : 390 : }
355 : :
356 : 13110 : void XmlStreamBuilder::appendClosingTag( int token )
357 : : {
358 [ + - ][ + - ]: 13110 : tags.push_back( Tag( CLOSING( token )));
[ + - ]
359 : 13110 : }
360 : :
361 : 2970 : void XmlStreamBuilder::appendCharacters( const rtl::OUString& chars )
362 : : {
363 : : assert( !tags.empty());
364 : 2970 : tags.back().text += chars;
365 : 2970 : }
366 : :
367 : : } // namespace
368 : : } // namespace
369 : :
370 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|