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/ustring.hxx>
39 :
40 : // *sigh*
41 : #define STR( str ) OUString( RTL_CONSTASCII_USTRINGPARAM( str ))
42 :
43 : #define OPENING( token ) XML_STREAM_OPENING( token )
44 : #define CLOSING( token ) XML_STREAM_CLOSING( token )
45 :
46 : using namespace com::sun::star;
47 : using rtl::OUString;
48 :
49 : namespace oox
50 : {
51 :
52 : namespace formulaimport
53 : {
54 :
55 : namespace
56 : {
57 : // a class that inherits from AttributeList, builds the internal data and then will be sliced off
58 : // during conversion to the base class
59 9638 : class AttributeListBuilder
60 : : public XmlStream::AttributeList
61 : {
62 : public:
63 : AttributeListBuilder( const uno::Reference< xml::sax::XFastAttributeList >& a );
64 : };
65 :
66 9638 : AttributeListBuilder::AttributeListBuilder( const uno::Reference< xml::sax::XFastAttributeList >& a )
67 : {
68 9638 : if( a.get() == NULL )
69 9638 : return;
70 2353 : uno::Sequence< xml::FastAttribute > aFastAttrSeq = a->getFastAttributes();
71 2353 : const xml::FastAttribute* pFastAttr = aFastAttrSeq.getConstArray();
72 2353 : sal_Int32 nFastAttrLength = aFastAttrSeq.getLength();
73 3516 : for( int i = 0;
74 : i < nFastAttrLength;
75 : ++i )
76 : {
77 1163 : attrs[ pFastAttr[ i ].Token ] = pFastAttr[ i ].Value;
78 2353 : }
79 : }
80 :
81 0 : static OUString tokenToString( int token )
82 : {
83 0 : OUString tokenname = StaticTokenMap::get().getUnicodeTokenName( token & TOKEN_MASK );
84 0 : if( tokenname.isEmpty())
85 0 : tokenname = STR( "???" );
86 0 : int nmsp = ( token & NMSP_MASK & ~( TAG_OPENING | TAG_CLOSING ));
87 : #if 0 // this is awfully long
88 : OUString namespacename = StaticNamespaceMap::get().count( nmsp ) != 0
89 : ? StaticNamespaceMap::get()[ nmsp ] : STR( "???" );
90 : #else
91 0 : OUString namespacename;
92 : // only few are needed actually
93 0 : switch( nmsp )
94 : {
95 : case NMSP_officeMath:
96 0 : namespacename = STR( "m" );
97 0 : break;
98 : case NMSP_doc:
99 0 : namespacename = STR( "w" );
100 0 : break;
101 : default:
102 0 : namespacename = STR( "?" );
103 0 : break;
104 : }
105 : #endif
106 0 : if( token == OPENING( token ))
107 0 : return STR( "<" ) + namespacename + STR( ":" ) + tokenname + STR ( ">" );
108 0 : if( token == CLOSING( token ))
109 0 : return STR( "</" ) + namespacename + STR( ":" ) + tokenname + STR ( ">" );
110 : // just the name itself, not specified whether opening or closing
111 0 : return namespacename + STR( ":" ) + tokenname;
112 : }
113 :
114 : } // namespace
115 :
116 130 : OUString& XmlStream::AttributeList::operator[] (int token)
117 : {
118 130 : return attrs[token];
119 : }
120 :
121 1117 : rtl::OUString XmlStream::AttributeList::attribute( int token, const rtl::OUString& def ) const
122 : {
123 1117 : std::map< int, rtl::OUString >::const_iterator find = attrs.find( token );
124 1117 : if( find != attrs.end())
125 514 : return find->second;
126 603 : return def;
127 : }
128 :
129 20 : bool XmlStream::AttributeList::attribute( int token, bool def ) const
130 : {
131 20 : std::map< int, rtl::OUString >::const_iterator find = attrs.find( token );
132 20 : if( find != attrs.end())
133 : {
134 20 : const rtl::OUString sValue = find->second;
135 68 : if( sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("true")) ||
136 20 : sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("on")) ||
137 14 : sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("t")) ||
138 14 : sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("1")) )
139 20 : return true;
140 0 : if( sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("false")) ||
141 0 : sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("off")) ||
142 0 : sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("f")) ||
143 0 : sValue.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("0")) )
144 0 : return false;
145 20 : SAL_WARN( "oox.xmlstream", "Cannot convert \'" << sValue << "\' to bool." );
146 : }
147 0 : return def;
148 : }
149 :
150 78 : sal_Unicode XmlStream::AttributeList::attribute( int token, sal_Unicode def ) const
151 : {
152 78 : std::map< int, rtl::OUString >::const_iterator find = attrs.find( token );
153 78 : if( find != attrs.end())
154 : {
155 78 : if( !find->second.isEmpty() )
156 : {
157 78 : if( find->second.getLength() != 1 )
158 : SAL_WARN( "oox.xmlstream", "Cannot convert \'" << find->second << "\' to sal_Unicode, stripping." );
159 78 : return find->second[ 0 ];
160 : }
161 : }
162 0 : return def;
163 : }
164 :
165 9638 : XmlStream::Tag::Tag( int t, const uno::Reference< xml::sax::XFastAttributeList >& a, const rtl::OUString& txt )
166 : : token( t )
167 : , attributes( AttributeListBuilder( a ))
168 9638 : , text( txt )
169 : {
170 9638 : }
171 :
172 130 : XmlStream::Tag::Tag( int t, const AttributeList& a )
173 : : token( t )
174 130 : , attributes( a )
175 : {
176 130 : }
177 :
178 :
179 1648 : XmlStream::Tag::operator bool() const
180 : {
181 1648 : return token != XML_TOKEN_INVALID;
182 : }
183 :
184 282 : XmlStream::XmlStream()
185 282 : : pos( 0 )
186 : {
187 : // make sure our extra bit does not conflict with values used by oox
188 : assert( TAG_OPENING > ( 1024 << NMSP_SHIFT ));
189 282 : }
190 :
191 9917 : bool XmlStream::atEnd() const
192 : {
193 9917 : return pos >= tags.size();
194 : }
195 :
196 7640 : XmlStream::Tag XmlStream::currentTag() const
197 : {
198 7640 : if( pos >= tags.size())
199 0 : return Tag();
200 7640 : return tags[ pos ];
201 : }
202 :
203 37524 : int XmlStream::currentToken() const
204 : {
205 37524 : if( pos >= tags.size())
206 0 : return XML_TOKEN_INVALID;
207 37524 : return tags[ pos ].token;
208 : }
209 :
210 11538 : void XmlStream::moveToNextTag()
211 : {
212 11538 : if( pos < tags.size())
213 11538 : ++pos;
214 11538 : }
215 :
216 3173 : XmlStream::Tag XmlStream::ensureOpeningTag( int token )
217 : {
218 3173 : return checkTag( OPENING( token ), false );
219 : }
220 :
221 1648 : XmlStream::Tag XmlStream::checkOpeningTag( int token )
222 : {
223 1648 : return checkTag( OPENING( token ), true );
224 : }
225 :
226 3820 : void XmlStream::ensureClosingTag( int token )
227 : {
228 3820 : checkTag( CLOSING( token ), false );
229 3820 : }
230 :
231 8641 : XmlStream::Tag XmlStream::checkTag( int token, bool optional )
232 : {
233 : // either it's the following tag, or find it
234 8641 : int savedPos = pos;
235 8641 : if( optional )
236 : { // avoid printing debug messages about skipping tags if the optional one
237 : // will not be found and the position will be reset back
238 1648 : if( currentToken() != token && !findTagInternal( token, true ))
239 : {
240 1001 : pos = savedPos;
241 1001 : return Tag();
242 : }
243 : }
244 7640 : if( currentToken() == token || findTag( token ))
245 : {
246 7640 : Tag ret = currentTag();
247 7640 : moveToNextTag();
248 7640 : return ret; // ok
249 : }
250 0 : if( optional )
251 : { // not a problem, just rewind
252 0 : pos = savedPos;
253 0 : return Tag();
254 : }
255 : SAL_WARN( "oox.xmlstream", "Expected tag " << tokenToString( token ) << " not found." );
256 0 : return Tag();
257 : }
258 :
259 565 : bool XmlStream::findTag( int token )
260 : {
261 565 : return findTagInternal( token, false );
262 : }
263 :
264 1585 : bool XmlStream::findTagInternal( int token, bool silent )
265 : {
266 1585 : int depth = 0;
267 7068 : for(;
268 5483 : !atEnd();
269 3898 : moveToNextTag())
270 : {
271 5483 : if( depth > 0 ) // we're inside a nested element, skip those
272 : {
273 2502 : if( currentToken() == OPENING( currentToken()))
274 : {
275 553 : if( !silent )
276 : SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
277 553 : ++depth;
278 : }
279 1949 : else if( currentToken() == CLOSING( currentToken()))
280 : {
281 1949 : if( !silent )
282 : SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
283 1949 : --depth;
284 : }
285 : else
286 : {
287 0 : if( !silent )
288 : SAL_WARN( "oox.xmlstream", "Malformed token " << currentToken() << " ("
289 : << tokenToString( currentToken()) << ")" );
290 0 : abort();
291 : }
292 2502 : continue;
293 : }
294 2981 : if( currentToken() == token )
295 475 : return true; // ok, found
296 2506 : if( currentToken() == CLOSING( currentToken()))
297 1110 : return false; // that would be leaving current element, so not found
298 1396 : if( currentToken() == OPENING( currentToken()))
299 : {
300 1396 : if( !silent )
301 : SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
302 1396 : ++depth;
303 : }
304 : else
305 0 : abort();
306 : }
307 0 : if( !silent )
308 : SAL_WARN( "oox.xmlstream", "Unexpected end of stream reached." );
309 0 : return false;
310 : }
311 :
312 0 : void XmlStream::skipElementInternal( int token, bool silent )
313 : {
314 0 : int closing = ( token & ~TAG_OPENING ) | TAG_CLOSING; // make it a closing tag
315 : assert( currentToken() == OPENING( token ));
316 0 : if( !silent )
317 : SAL_INFO( "oox.xmlstream", "Skipping unexpected element " << tokenToString( currentToken()));
318 0 : moveToNextTag();
319 : // and just find the matching closing tag
320 0 : if( findTag( closing ))
321 : {
322 0 : if( !silent )
323 : SAL_INFO( "oox.xmlstream", "Skipped unexpected element " << tokenToString( token ));
324 0 : moveToNextTag(); // and skip it too
325 0 : return;
326 : }
327 : // this one is an unexpected problem, do not silent it
328 : SAL_WARN( "oox.xmlstream", "Expected end of element " << tokenToString( token ) << " not found." );
329 : }
330 :
331 0 : void XmlStream::handleUnexpectedTag()
332 : {
333 0 : if( atEnd())
334 0 : return;
335 0 : if( currentToken() == CLOSING( currentToken()))
336 : {
337 : SAL_INFO( "oox.xmlstream", "Skipping unexpected tag " << tokenToString( currentToken()));
338 0 : moveToNextTag(); // just skip it
339 0 : return;
340 : }
341 0 : skipElementInternal( currentToken(), false ); // otherwise skip the entire element
342 : }
343 :
344 :
345 4255 : void XmlStreamBuilder::appendOpeningTag( int token, const uno::Reference< xml::sax::XFastAttributeList >& attrs )
346 : {
347 4255 : tags.push_back( Tag( OPENING( token ), attrs ));
348 4255 : }
349 :
350 130 : void XmlStreamBuilder::appendOpeningTag( int token, const AttributeList& attrs )
351 : {
352 130 : tags.push_back( Tag( OPENING( token ), attrs ));
353 130 : }
354 :
355 4382 : void XmlStreamBuilder::appendClosingTag( int token )
356 : {
357 4382 : tags.push_back( Tag( CLOSING( token )));
358 4382 : }
359 :
360 993 : void XmlStreamBuilder::appendCharacters( const rtl::OUString& chars )
361 : {
362 : assert( !tags.empty());
363 993 : tags.back().text += chars;
364 993 : }
365 :
366 : } // namespace
367 : } // namespace
368 :
369 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|