Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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 : */
9 :
10 : #include "oox/mathml/importutils.hxx"
11 :
12 : #include <assert.h>
13 : #include <stdio.h>
14 :
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>
20 :
21 : #define OPENING( token ) XML_STREAM_OPENING( token )
22 : #define CLOSING( token ) XML_STREAM_CLOSING( token )
23 :
24 : using namespace com::sun::star;
25 :
26 : namespace oox
27 : {
28 :
29 : namespace formulaimport
30 : {
31 :
32 : namespace
33 : {
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 34892 : class AttributeListBuilder
37 : : public XmlStream::AttributeList
38 : {
39 : public:
40 : AttributeListBuilder( const uno::Reference< xml::sax::XFastAttributeList >& a );
41 : };
42 :
43 34892 : AttributeListBuilder::AttributeListBuilder( const uno::Reference< xml::sax::XFastAttributeList >& a )
44 : {
45 34892 : if( a.get() == NULL )
46 59120 : return;
47 10664 : uno::Sequence< xml::FastAttribute > aFastAttrSeq = a->getFastAttributes();
48 10664 : const xml::FastAttribute* pFastAttr = aFastAttrSeq.getConstArray();
49 10664 : sal_Int32 nFastAttrLength = aFastAttrSeq.getLength();
50 15848 : for( int i = 0;
51 : i < nFastAttrLength;
52 : ++i )
53 : {
54 5184 : attrs[ pFastAttr[ i ].Token ] = pFastAttr[ i ].Value;
55 10664 : }
56 : }
57 :
58 0 : static OString tokenToString( int token )
59 : {
60 0 : const uno::Sequence< sal_Int8 > aTokenNameSeq = StaticTokenMap::get().getUtf8TokenName( token & TOKEN_MASK );
61 0 : OString tokenname( reinterpret_cast< const char* >( aTokenNameSeq.getConstArray() ), aTokenNameSeq.getLength() );
62 0 : if( tokenname.isEmpty())
63 0 : tokenname = "???";
64 0 : int nmsp = ( token & NMSP_MASK & ~( TAG_OPENING | TAG_CLOSING ));
65 : #if 0 // this is awfully long
66 : OString namespacename = StaticNamespaceMap::get().count( nmsp ) != 0
67 : ? StaticNamespaceMap::get()[ nmsp ] : OString( "???" );
68 : #else
69 0 : OString namespacename;
70 : // only few are needed actually
71 0 : switch( nmsp )
72 : {
73 : case NMSP_officeMath:
74 0 : namespacename = "m";
75 0 : break;
76 : case NMSP_doc:
77 0 : namespacename = "w";
78 0 : break;
79 : default:
80 0 : namespacename = "?";
81 0 : break;
82 : }
83 : #endif
84 0 : if( token == OPENING( token ))
85 0 : return "<" + namespacename + ":" + tokenname + ">";
86 0 : if( token == CLOSING( token ))
87 0 : return "</" + namespacename + ":" + tokenname + ">";
88 : // just the name itself, not specified whether opening or closing
89 0 : return namespacename + ":" + tokenname;
90 : }
91 :
92 : } // namespace
93 :
94 338 : OUString& XmlStream::AttributeList::operator[] (int token)
95 : {
96 338 : return attrs[token];
97 : }
98 :
99 3494 : OUString XmlStream::AttributeList::attribute( int token, const OUString& def ) const
100 : {
101 3494 : std::map< int, OUString >::const_iterator find = attrs.find( token );
102 3494 : if( find != attrs.end())
103 1734 : return find->second;
104 1760 : return def;
105 : }
106 :
107 144 : bool XmlStream::AttributeList::attribute( int token, bool def ) const
108 : {
109 144 : std::map< int, OUString >::const_iterator find = attrs.find( token );
110 144 : if( find != attrs.end())
111 : {
112 74 : const OUString sValue = find->second;
113 222 : if( sValue.equalsIgnoreAsciiCase("true") ||
114 134 : sValue.equalsIgnoreAsciiCase("on") ||
115 194 : sValue.equalsIgnoreAsciiCase("t") ||
116 60 : sValue.equalsIgnoreAsciiCase("1") )
117 74 : return true;
118 0 : if( sValue.equalsIgnoreAsciiCase("false") ||
119 0 : sValue.equalsIgnoreAsciiCase("off") ||
120 0 : sValue.equalsIgnoreAsciiCase("f") ||
121 0 : sValue.equalsIgnoreAsciiCase("0") )
122 0 : return false;
123 0 : SAL_WARN( "oox.xmlstream", "Cannot convert \'" << sValue << "\' to bool." );
124 : }
125 70 : return def;
126 : }
127 :
128 254 : sal_Unicode XmlStream::AttributeList::attribute( int token, sal_Unicode def ) const
129 : {
130 254 : std::map< int, OUString >::const_iterator find = attrs.find( token );
131 254 : if( find != attrs.end())
132 : {
133 254 : if( !find->second.isEmpty() )
134 : {
135 254 : if( find->second.getLength() != 1 )
136 : SAL_WARN( "oox.xmlstream", "Cannot convert \'" << find->second << "\' to sal_Unicode, stripping." );
137 254 : return find->second[ 0 ];
138 : }
139 : }
140 0 : return def;
141 : }
142 :
143 34892 : XmlStream::Tag::Tag( int t, const uno::Reference< xml::sax::XFastAttributeList >& a, const OUString& txt )
144 : : token( t )
145 : , attributes( AttributeListBuilder( a ))
146 34892 : , text( txt )
147 : {
148 34892 : }
149 :
150 338 : XmlStream::Tag::Tag( int t, const AttributeList& a )
151 : : token( t )
152 338 : , attributes( a )
153 : {
154 338 : }
155 :
156 5608 : XmlStream::Tag::operator bool() const
157 : {
158 5608 : return token != XML_TOKEN_INVALID;
159 : }
160 :
161 1352 : XmlStream::XmlStream()
162 1352 : : pos( 0 )
163 : {
164 : // make sure our extra bit does not conflict with values used by oox
165 : assert( TAG_OPENING > ( 1024 << NMSP_SHIFT ));
166 1352 : }
167 :
168 41592 : bool XmlStream::atEnd() const
169 : {
170 41592 : return pos >= tags.size();
171 : }
172 :
173 23784 : XmlStream::Tag XmlStream::currentTag() const
174 : {
175 23784 : if( pos >= tags.size())
176 0 : return Tag();
177 23784 : return tags[ pos ];
178 : }
179 :
180 154160 : int XmlStream::currentToken() const
181 : {
182 154160 : if( pos >= tags.size())
183 0 : return XML_TOKEN_INVALID;
184 154160 : return tags[ pos ].token;
185 : }
186 :
187 44988 : void XmlStream::moveToNextTag()
188 : {
189 44988 : if( pos < tags.size())
190 44988 : ++pos;
191 44988 : }
192 :
193 10102 : XmlStream::Tag XmlStream::ensureOpeningTag( int token )
194 : {
195 10102 : return checkTag( OPENING( token ), false );
196 : }
197 :
198 5608 : XmlStream::Tag XmlStream::checkOpeningTag( int token )
199 : {
200 5608 : return checkTag( OPENING( token ), true );
201 : }
202 :
203 11892 : void XmlStream::ensureClosingTag( int token )
204 : {
205 11892 : checkTag( CLOSING( token ), false );
206 11892 : }
207 :
208 27602 : XmlStream::Tag XmlStream::checkTag( int token, bool optional )
209 : {
210 : // either it's the following tag, or find it
211 27602 : int savedPos = pos;
212 27602 : if( optional )
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 5608 : if( currentToken() != token && !findTagInternal( token, true ))
216 : {
217 3818 : pos = savedPos;
218 3818 : return Tag();
219 : }
220 : }
221 23784 : if( currentToken() == token || findTag( token ))
222 : {
223 23784 : Tag ret = currentTag();
224 23784 : moveToNextTag();
225 23784 : return ret; // ok
226 : }
227 0 : if( optional )
228 : { // not a problem, just rewind
229 0 : pos = savedPos;
230 0 : return Tag();
231 : }
232 : SAL_WARN( "oox.xmlstream", "Expected tag " << tokenToString( token ) << " not found." );
233 0 : return Tag();
234 : }
235 :
236 2354 : bool XmlStream::findTag( int token )
237 : {
238 2354 : return findTagInternal( token, false );
239 : }
240 :
241 6178 : bool XmlStream::findTagInternal( int token, bool silent )
242 : {
243 6178 : int depth = 0;
244 31808 : for(;
245 25630 : !atEnd();
246 19452 : moveToNextTag())
247 : {
248 25630 : if( depth > 0 ) // we're inside a nested element, skip those
249 : {
250 12938 : if( currentToken() == OPENING( currentToken()))
251 : {
252 3212 : if( !silent )
253 : SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
254 3212 : ++depth;
255 : }
256 9726 : else if( currentToken() == CLOSING( currentToken()))
257 : {
258 9726 : if( !silent )
259 : SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
260 9726 : --depth;
261 : }
262 : else
263 : {
264 0 : if( !silent )
265 : SAL_WARN( "oox.xmlstream", "Malformed token " << currentToken() << " ("
266 : << tokenToString( currentToken()) << ")" );
267 0 : abort();
268 : }
269 12938 : continue;
270 : }
271 12692 : if( currentToken() == token )
272 2006 : return true; // ok, found
273 10686 : if( currentToken() == CLOSING( currentToken()))
274 4172 : return false; // that would be leaving current element, so not found
275 6514 : if( currentToken() == OPENING( currentToken()))
276 : {
277 6514 : if( !silent )
278 : SAL_INFO( "oox.xmlstream", "Skipping tag " << tokenToString( currentToken()));
279 6514 : ++depth;
280 : }
281 : else
282 0 : abort();
283 : }
284 0 : if( !silent )
285 : SAL_WARN( "oox.xmlstream", "Unexpected end of stream reached." );
286 0 : return false;
287 : }
288 :
289 876 : void XmlStream::skipElementInternal( int token, bool silent )
290 : {
291 876 : int closing = ( token & ~TAG_OPENING ) | TAG_CLOSING; // make it a closing tag
292 : assert( currentToken() == OPENING( token ));
293 876 : if( !silent )
294 : SAL_INFO( "oox.xmlstream", "Skipping unexpected element " << tokenToString( currentToken()));
295 876 : moveToNextTag();
296 : // and just find the matching closing tag
297 876 : if( findTag( closing ))
298 : {
299 876 : if( !silent )
300 : SAL_INFO( "oox.xmlstream", "Skipped unexpected element " << tokenToString( token ));
301 876 : moveToNextTag(); // and skip it too
302 876 : return;
303 : }
304 : // this one is an unexpected problem, do not silent it
305 : SAL_WARN( "oox.xmlstream", "Expected end of element " << tokenToString( token ) << " not found." );
306 : }
307 :
308 876 : void XmlStream::handleUnexpectedTag()
309 : {
310 876 : if( atEnd())
311 0 : return;
312 876 : if( currentToken() == CLOSING( currentToken()))
313 : {
314 : SAL_INFO( "oox.xmlstream", "Skipping unexpected tag " << tokenToString( currentToken()));
315 0 : moveToNextTag(); // just skip it
316 0 : return;
317 : }
318 876 : skipElementInternal( currentToken(), false ); // otherwise skip the entire element
319 : }
320 :
321 15374 : void XmlStreamBuilder::appendOpeningTag( int token, const uno::Reference< xml::sax::XFastAttributeList >& attrs )
322 : {
323 15374 : tags.push_back( Tag( OPENING( token ), attrs ));
324 15374 : }
325 :
326 338 : void XmlStreamBuilder::appendOpeningTag( int token, const AttributeList& attrs )
327 : {
328 338 : tags.push_back( Tag( OPENING( token ), attrs ));
329 338 : }
330 :
331 15700 : void XmlStreamBuilder::appendClosingTag( int token )
332 : {
333 15700 : tags.push_back( Tag( CLOSING( token )));
334 15700 : }
335 :
336 3078 : void XmlStreamBuilder::appendCharacters( const OUString& chars )
337 : {
338 : assert( !tags.empty());
339 3078 : tags.back().text += chars;
340 3078 : }
341 :
342 : } // namespace
343 : } // namespace
344 :
345 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|