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