Marble

GeoParser.cpp
1 /*
2  SPDX-FileCopyrightText: 2008 Nikolas Zimmermann <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 
8 // Own
9 #include "GeoParser.h"
10 
11 // Marble
12 #include "MarbleDebug.h"
13 
14 // Geodata
15 #include "GeoDocument.h"
16 #include "GeoTagHandler.h"
17 
18 namespace Marble
19 {
20 
21 // Set to a value greater than 0, to dump parent node chain while parsing
22 #define DUMP_PARENT_STACK 0
23 
24 GeoParser::GeoParser( GeoDataGenericSourceType source )
25  : QXmlStreamReader(),
26  m_document( nullptr ),
27  m_source( source )
28 {
29 }
30 
31 GeoParser::~GeoParser()
32 {
33  delete m_document;
34 }
35 
36 #if DUMP_PARENT_STACK > 0
37 static void dumpParentStack( const QString& name, int size, bool close )
38 {
39  static int depth = 0;
40 
41  if ( !close )
42  depth++;
43 
44  QString result;
45  for ( int i = 0; i < depth; ++i )
46  result += QLatin1Char(' ');
47 
48  if ( close ) {
49  depth--;
50  result += QLatin1String("</");
51  } else
52  result += QLatin1Char('<');
53 
54  result += name + QLatin1String("> stack size ") + QString::number(size);
55  fprintf( stderr, "%s\n", qPrintable( result ));
56 }
57 #endif
58 
59 bool GeoParser::read( QIODevice* device )
60 {
61  // Assert previous document got released.
62  Q_ASSERT( !m_document );
63  m_document = createDocument();
64  Q_ASSERT( m_document );
65 
66  // Set data source
67  setDevice( device );
68 
69  // Start parsing
70  while ( !atEnd() ) {
71  readNext();
72 
73  if ( isStartElement() ) {
74  if ( isValidRootElement() ) {
75 #if DUMP_PARENT_STACK > 0
76  dumpParentStack( name().toString(), m_nodeStack.size(), false );
77 #endif
78 
79  parseDocument();
80 
81  if ( !m_nodeStack.isEmpty() )
82  raiseError(
83  // Keep trailing space in both strings, to match translated string
84  // TODO: check if that space is kept through the tool pipeline
85  //~ singular Parsing failed line %1. Still %n unclosed tag after document end.
86  //~ plural Parsing failed line %1. Still %n unclosed tags after document end.
87  QObject::tr("Parsing failed line %1. Still %n unclosed tag(s) after document end. ", "",
88  m_nodeStack.size() ).arg( lineNumber() ) + errorString());
89  } else
90  return false;
91  }
92  }
93 
94  if ( error() ) {
95  if ( lineNumber() == 1) {
96  raiseError(QString());
97  }
98  // Defer the deletion to the dtor
99  // This allows the BookmarkManager to recover the broken .kml files it produced in Marble 1.0 and 1.1
100  /** @todo: Remove this workaround around Marble 1.4 */
101  // delete releaseDocument();
102  }
103  return !error();
104 }
105 
106 bool GeoParser::isValidElement( const QString& tagName ) const
107 {
108  return name() == tagName;
109 }
110 
111 GeoStackItem GeoParser::parentElement( unsigned int depth ) const
112 {
113  QStack<GeoStackItem>::const_iterator it = m_nodeStack.constEnd() - 1;
114 
115  if ( it - depth < m_nodeStack.constBegin() )
116  return GeoStackItem();
117 
118  return *(it - depth);
119 }
120 
121 void GeoParser::parseDocument()
122 {
123  if( !isStartElement() ) {
124  raiseError( QObject::tr("Error parsing file at line: %1 and column %2 . ")
125  .arg( lineNumber() ).arg( columnNumber() )
126  + QObject::tr("This is an Invalid File") );
127  return;
128  }
129 
130  bool processChildren = true;
131  QualifiedName qName( name().toString(), namespaceUri().toString() );
132 
133  if( tokenType() == QXmlStreamReader::Invalid )
134  raiseWarning( QString( "%1: %2" ).arg( error() ).arg( errorString() ) );
135 
136  GeoStackItem stackItem( qName, nullptr );
137 
138  if ( const GeoTagHandler* handler = GeoTagHandler::recognizes( qName )) {
139  stackItem.assignNode( handler->parse( *this ));
140  processChildren = !isEndElement();
141  }
142  // Only add GeoStackItem to the parent chain, if the tag handler
143  // for the current element possibly contains non-textual children.
144  // Consider following DGML snippet "<name>Test</name>" - the
145  // DGMLNameTagHandler assumes that <name> only contains textual
146  // children, and reads the joined value of all children using
147  // readElementText(). This implicates that tags like <name>
148  // don't contain any children that would need to be processed using
149  // this parseDocument() function.
150  if ( processChildren ) {
151  m_nodeStack.push( stackItem );
152 #if DUMP_PARENT_STACK > 0
153  dumpParentStack( name().toString(), m_nodeStack.size(), false );
154 #endif
155  while ( !atEnd() ) {
156  readNext();
157  if ( isEndElement() ) {
158  m_nodeStack.pop();
159 #if DUMP_PARENT_STACK > 0
160  dumpParentStack( name().toString(), m_nodeStack.size(), true );
161 #endif
162  break;
163  }
164 
165  if ( isStartElement() ) {
166  parseDocument();
167  }
168  }
169  }
170 #if DUMP_PARENT_STACK > 0
171  else {
172  // This is only used for debugging purposes.
173  m_nodeStack.push( stackItem );
174  dumpParentStack(name().toString() + QLatin1String("-discarded"), m_nodeStack.size(), false);
175 
176  m_nodeStack.pop();
177  dumpParentStack(name().toString() + QLatin1String("-discarded"), m_nodeStack.size(), true);
178  }
179 #endif
180 }
181 
182 void GeoParser::raiseWarning( const QString& warning )
183 {
184  // TODO: Maybe introduce a strict parsing mode where we feed the warning to
185  // raiseError() (which stops parsing).
186  mDebug() << "[GeoParser::raiseWarning] -> " << warning;
187 }
188 
189 QString GeoParser::attribute( const char* attributeName ) const
190 {
191  return attributes().value(QLatin1String(attributeName)).toString();
192 }
193 
194 GeoDocument* GeoParser::releaseDocument()
195 {
196  GeoDocument* document = m_document;
197  m_document = nullptr;
198  return document;
199 }
200 
201 }
QString number(int n, int base)
QVector::const_iterator constEnd() const const
Binds a QML item to a specific geodetic location in screen coordinates.
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
const char * name(StandardAction id)
QString tr(const char *sourceText, const char *disambiguation, int n)
int size() const const
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
char * toString(const EngineQuery &query)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Sep 21 2023 04:12:26 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.