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