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