• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

marble

  • sources
  • kde-4.12
  • kdeedu
  • marble
  • tools
  • osm-addresses
  • pbf
PbfParser.cpp
Go to the documentation of this file.
1 //
2 // This file is part of the Marble Virtual Globe.
3 //
4 // This file is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Copyright 2011 Dennis Nienhüser <earthwings@gentoo.org>
10 //
11 // This file originates from the MoNav project where it was named pbfreader.h and
12 // Copyright 2010 Christian Vetter veaac.fdirct@gmail.com
13 //
14 
15 #include "PbfParser.h"
16 
17 #include <QDebug>
18 
19 #include <zlib.h>
20 
21 #include <fstream>
22 
23 #include <netinet/in.h>
24 
25 using namespace std;
26 using namespace OSMPBF;
27 
28 PbfParser::PbfParser() :
29  m_currentGroup( 0 ),
30  m_currentEntity( 0 ),
31  m_loadBlock( false )
32 {
33  GOOGLE_PROTOBUF_VERIFY_VERSION;
34 }
35 
36 bool PbfParser::parse( const QFileInfo &fileInfo, int pass, bool &needAnotherPass )
37 {
38  m_pass = pass;
39  needAnotherPass = pass < 2;
40 
41  QFile file( fileInfo.absoluteFilePath() );
42  if ( !file.open( QFile::ReadOnly ) ) {
43  qCritical() << "Unable to open file " << fileInfo.absoluteFilePath() << " for reading.";
44  return false;
45  }
46 
47  m_stream.setDevice( &file );
48  m_stream.setByteOrder( QDataStream::BigEndian );
49 
50  if ( !parseBlobHeader() ) {
51  return false;
52  }
53 
54  if ( m_blobHeader.type() != "OSMHeader" ) {
55  qCritical() << "Unable to parse blob header type " << m_blobHeader.type().c_str();
56  return false;
57  }
58 
59  if ( !parseBlob() ) {
60  return false;
61  }
62 
63  if ( !parseData() ) {
64  return false;
65  }
66 
67  m_loadBlock = true;
68 
69  while ( true ) {
70 
71  if ( m_loadBlock ) {
72  if ( !readNext() ) {
73  if ( pass == 1 ) {
74  m_referencedWays.clear();
75  } else if ( pass == 2 ) {
76  m_referencedNodes.clear();
77  }
78 
79  return true;
80  }
81  loadBlock();
82  loadGroup();
83  }
84 
85  switch ( m_mode ) {
86  case ModeNode:
87  parseNode();
88  break;
89  case ModeWay:
90  parseWay();
91  break;
92  case ModeRelation:
93  parseRelation();
94  break;
95  case ModeDense:
96  parseDense();
97  break;
98  }
99  }
100 
101  return true;
102 }
103 
104 bool PbfParser::parseBlobHeader()
105 {
106  int size( -1 );
107  m_stream >> size;
108 
109  if ( size < 0 ) {
110  qCritical() << "Invalid blob header size " << size;
111  return false;
112  }
113 
114  m_buffer.resize( size );
115  int readBytes = m_stream.readRawData( m_buffer.data(), size );
116  if ( readBytes != size ) {
117  qCritical() << "Unable to read blob header";
118  return false;
119  }
120 
121  if ( !m_blobHeader.ParseFromArray( m_buffer.constData(), size ) ) {
122  qCritical() << "Unable to parse blob header";
123  return false;
124  }
125 
126  return true;
127 }
128 
129 bool PbfParser::parseBlob()
130 {
131  int size = m_blobHeader.datasize();
132  if ( size < 0 ) {
133  qCritical() << "invalid blob size:" << size;
134  return false;
135  }
136 
137  m_buffer.resize( size );
138  int readBytes = m_stream.readRawData( m_buffer.data(), size );
139  if ( readBytes != size ) {
140  qCritical() << "failed to read blob";
141  return false;
142  }
143 
144  if ( !m_blob.ParseFromArray( m_buffer.constData(), size ) ) {
145  qCritical() << "failed to parse blob";
146  return false;
147  }
148 
149  if ( m_blob.has_raw() ) {
150  const std::string& data = m_blob.raw();
151  m_buffer.resize( data.size() );
152  for ( unsigned int i = 0; i < data.size(); ++i ) {
153  m_buffer[i] = data[i];
154  }
155  } else if ( m_blob.has_zlib_data() ) {
156  m_buffer.resize( m_blob.raw_size() );
157  z_stream zStream;
158  zStream.next_in = ( unsigned char* ) m_blob.zlib_data().data();
159  zStream.avail_in = m_blob.zlib_data().size();
160  zStream.next_out = ( unsigned char* ) m_buffer.data();
161  zStream.avail_out = m_blob.raw_size();
162  zStream.zalloc = Z_NULL;
163  zStream.zfree = Z_NULL;
164  zStream.opaque = Z_NULL;
165  int result = inflateInit( &zStream );
166  if ( result != Z_OK ) {
167  qCritical() << "failed to open zlib m_stream";
168  return false;
169  }
170  result = inflate( &zStream, Z_FINISH );
171  if ( result != Z_STREAM_END ) {
172  qCritical() << "failed to inflate zlib m_stream";
173  return false;
174  }
175  result = inflateEnd( &zStream );
176  if ( result != Z_OK ) {
177  qCritical() << "failed to close zlib m_stream";
178  return false;
179  }
180 
181  return true;
182  } else if ( m_blob.has_lzma_data() ) {
183  qCritical() << "No support for lzma decryption implemented, sorry.";
184  return false;
185  } else {
186  qCritical() << "Blob contains no data";
187  return false;
188  }
189 
190  return true;
191 }
192 
193 bool PbfParser::parseData()
194 {
195  if ( !m_headerBlock.ParseFromArray( m_buffer.data(), m_buffer.size() ) ) {
196  qCritical() << "failed to parse header block";
197  return false;
198  }
199 
200  for ( int i = 0; i < m_headerBlock.required_features_size(); ++i ) {
201  string const & feature = m_headerBlock.required_features( i );
202  if ( feature != "OsmSchema-V0.6" && feature != "DenseNodes" ) {
203  qCritical() << "Support for feature " << feature.c_str() << "not implemented";
204  return false;
205  }
206  }
207 
208  return true;
209 }
210 
211 bool PbfParser::readNext()
212 {
213  if ( !parseBlobHeader() )
214  return false;
215 
216  if ( m_blobHeader.type() != "OSMData" ) {
217  qCritical() << "invalid block type, found" << m_blobHeader.type().data() << "instead of OSMData";
218  return false;
219  }
220 
221  if ( !parseBlob() )
222  return false;
223 
224  if ( !m_primitiveBlock.ParseFromArray( m_buffer.data(), m_buffer.size() ) ) {
225  qCritical() << "failed to parse PrimitiveBlock";
226  return false;
227  }
228  return true;
229 }
230 
231 void PbfParser::loadGroup()
232 {
233  const PrimitiveGroup& group = m_primitiveBlock.primitivegroup( m_currentGroup );
234  if ( group.nodes_size() != 0 ) {
235  m_mode = ModeNode;
236  } else if ( group.ways_size() != 0 ) {
237  m_mode = ModeWay;
238  } else if ( group.relations_size() != 0 ) {
239  m_mode = ModeRelation;
240  } else if ( group.has_dense() ) {
241  m_mode = ModeDense;
242  m_lastDenseID = 0;
243  m_lastDenseTag = 0;
244  m_lastDenseLatitude = 0;
245  m_lastDenseLongitude = 0;
246  assert( group.dense().id_size() != 0 );
247  } else
248  assert( false );
249 }
250 
251 void PbfParser::loadBlock()
252 {
253  m_loadBlock = false;
254  m_currentGroup = 0;
255  m_currentEntity = 0;
256 }
257 
258 void PbfParser::parseNode()
259 {
260  if ( m_pass == 2 ) {
261  const Node& inputNode = m_primitiveBlock.primitivegroup( m_currentGroup ).nodes( m_currentEntity );
262  Marble::Node node;
263  node.lat = ( ( double ) inputNode.lat() * m_primitiveBlock.granularity() + m_primitiveBlock.lat_offset() ) / ( 1000.0 * 1000.0 * 1000.0 );
264  node.lon = ( ( double ) inputNode.lon() * m_primitiveBlock.granularity() + m_primitiveBlock.lon_offset() ) / ( 1000.0 * 1000.0 * 1000.0 );
265 
266  for ( int tag = 0; tag < inputNode.keys_size(); tag++ ) {
267 
268  QString key = QString::fromUtf8( m_primitiveBlock.stringtable().s( inputNode.keys( tag ) ).data() );
269  QString value = QString::fromUtf8( m_primitiveBlock.stringtable().s( inputNode.vals( tag ) ).data() );
270 
271  if ( key == "name" ) {
272  node.name = value.trimmed();
273  } else if ( key == "addr:street" ) {
274  node.street = value.trimmed();
275  node.save = true;
276  } else if ( key == "addr:housenumber" ) {
277  node.houseNumber = value;
278  node.save = true;
279  } else if ( key == "addr:city" ) {
280  node.city = value;
281  node.save = true;
282  } else {
283  if ( shouldSave( Marble::NodeType, key, value ) ) {
284  node.save = true;
285  }
286  setCategory( node, key, value );
287  }
288  }
289 
290  if ( node.save ) {
291  m_nodes[inputNode.id()] = node;
292  }
293 
294  if ( m_referencedNodes.contains( inputNode.id() ) ) {
295  m_coordinates[inputNode.id()] = node;
296  }
297  }
298 
299  m_currentEntity++;
300  if ( m_currentEntity >= m_primitiveBlock.primitivegroup( m_currentGroup ).nodes_size() ) {
301  m_currentEntity = 0;
302  m_currentGroup++;
303  if ( m_currentGroup >= m_primitiveBlock.primitivegroup_size() )
304  m_loadBlock = true;
305  else
306  loadGroup();
307  }
308 }
309 
310 void PbfParser::parseWay()
311 {
312  if ( m_pass == 1 ) {
313  const Way& inputWay = m_primitiveBlock.primitivegroup( m_currentGroup ).ways( m_currentEntity );
314  Marble::Way way;
315  Marble::Relation relation;
316 
317  for ( int tag = 0; tag < inputWay.keys_size(); tag++ ) {
318  QString key = QString::fromUtf8( m_primitiveBlock.stringtable().s( inputWay.keys( tag ) ).data() );
319  QString value = QString::fromUtf8( m_primitiveBlock.stringtable().s( inputWay.vals( tag ) ).data() );
320 
321  if ( key == "name" ) {
322  way.name = value.trimmed();
323  } else if ( key == "addr:street" ) {
324  way.street = value.trimmed();
325  way.save = true;
326  } else if ( key == "addr:housenumber" ) {
327  way.houseNumber = value;
328  way.save = true;
329  } else if ( key == "addr:city" ) {
330  way.city = value;
331  way.save = true;
332  } else if ( key == "building" && value == "yes" ) {
333  way.isBuilding = true;
334  } else if ( key == "boundary" && value == "administrative" ) {
335  relation.isAdministrativeBoundary = true;
336  } else if ( key == "admin_level" ) {
337  relation.adminLevel = value.toInt();
338  } else {
339  if ( shouldSave( Marble::WayType, key, value ) ) {
340  way.save = true;
341  }
342  setCategory( way, key, value );
343  }
344  }
345 
346  long long lastRef = 0;
347  for ( int i = 0; i < inputWay.refs_size(); i++ ) {
348  lastRef += inputWay.refs( i );
349  way.nodes.push_back( lastRef );
350  }
351 
352  if ( relation.isAdministrativeBoundary && !way.name.isEmpty() ) {
353  relation.name = way.name;
354  relation.ways << QPair<int, Marble::RelationRole>( inputWay.id(), Marble::Outer );
355  m_relations[inputWay.id()] = relation;
356  }
357 
358  if ( way.save || m_referencedWays.contains( inputWay.id() ) ) {
359  if ( !way.isBuilding && way.nodes.size() > 1 && !m_referencedWays.contains( inputWay.id() ) ) {
360  QList<int> nodes = way.nodes;
361  way.nodes.clear();
362  way.nodes << nodes.first();
363  if ( nodes.size() > 2 ) {
364  way.nodes << nodes.at( nodes.size() / 2 );
365  }
366  way.nodes << nodes.last();
367  }
368 
369  foreach( int node, way.nodes ) {
370  m_referencedNodes << node;
371  }
372 
373  m_ways[inputWay.id()] = way;
374  }
375  }
376 
377  m_currentEntity++;
378  if ( m_currentEntity >= m_primitiveBlock.primitivegroup( m_currentGroup ).ways_size() ) {
379  m_currentEntity = 0;
380  m_currentGroup++;
381  if ( m_currentGroup >= m_primitiveBlock.primitivegroup_size() )
382  m_loadBlock = true;
383  else
384  loadGroup();
385  }
386 }
387 
388 void PbfParser::parseRelation()
389 {
390  if ( m_pass == 0 ) {
391  const Relation& inputRelation = m_primitiveBlock.primitivegroup( m_currentGroup ).relations( m_currentEntity );
392  Marble::Relation relation;
393 
394  for ( int tag = 0; tag < inputRelation.keys_size(); tag++ ) {
395 
396  QString key = QString::fromUtf8( m_primitiveBlock.stringtable().s( inputRelation.keys( tag ) ).data() );
397  QString value = QString::fromUtf8( m_primitiveBlock.stringtable().s( inputRelation.vals( tag ) ).data() );
398 
399  if ( key == "boundary" && value == "administrative" ) {
400  relation.isAdministrativeBoundary = true;
401  } else if ( key == "admin_level" ) {
402  relation.adminLevel = value.toInt();
403  } else if ( key == "name" ) {
404  relation.name = value.trimmed();
405  } else if ( key == "type" && value == "multipolygon" ) {
406  relation.isMultipolygon = true;
407  }
408  }
409 
410  if ( relation.isAdministrativeBoundary ) {
411  long long lastRef = 0;
412  for ( int i = 0; i < inputRelation.types_size(); i++ ) {
413  lastRef += inputRelation.memids( i );
414  switch ( inputRelation.types( i ) ) {
415  case OSMPBF::Relation::NODE:
416  relation.nodes.push_back( lastRef );
417  break;
418  case OSMPBF::Relation::WAY: {
419  string role = m_primitiveBlock.stringtable().s( inputRelation.roles_sid( i ) ).data();
420  Marble::RelationRole relationRole = Marble::None;
421  if ( role == "outer" ) relationRole = Marble::Outer;
422  if ( role == "inner" ) relationRole = Marble::Inner;
423  m_referencedWays << lastRef;
424  relation.ways.push_back( QPair<int, Marble::RelationRole>( lastRef, relationRole ) );
425  }
426  break;
427  case OSMPBF::Relation::RELATION:
428  relation.relations.push_back( lastRef );
429  }
430  }
431 
432  m_relations[inputRelation.id()] = relation;
433  }
434  }
435 
436  m_currentEntity++;
437  if ( m_currentEntity >= m_primitiveBlock.primitivegroup( m_currentGroup ).relations_size() ) {
438  m_currentEntity = 0;
439  m_currentGroup++;
440  if ( m_currentGroup >= m_primitiveBlock.primitivegroup_size() )
441  m_loadBlock = true;
442  else
443  loadGroup();
444  }
445 }
446 
447 void PbfParser::parseDense()
448 {
449  const DenseNodes& dense = m_primitiveBlock.primitivegroup( m_currentGroup ).dense();
450  if ( m_pass == 2 ) {
451  m_lastDenseID += dense.id( m_currentEntity );
452  m_lastDenseLatitude += dense.lat( m_currentEntity );
453  m_lastDenseLongitude += dense.lon( m_currentEntity );
454 
455  Marble::Node node;
456  node.lat = ( ( double ) m_lastDenseLatitude * m_primitiveBlock.granularity() + m_primitiveBlock.lat_offset() ) / ( 1000.0 * 1000.0 * 1000.0 );
457  node.lon = ( ( double ) m_lastDenseLongitude * m_primitiveBlock.granularity() + m_primitiveBlock.lon_offset() ) / ( 1000.0 * 1000.0 * 1000.0 );
458 
459  while ( true ) {
460  if ( m_lastDenseTag >= dense.keys_vals_size() )
461  break;
462 
463  int tagValue = dense.keys_vals( m_lastDenseTag );
464  if ( tagValue == 0 ) {
465  m_lastDenseTag++;
466  break;
467  }
468 
469  QString key = QString::fromUtf8( m_primitiveBlock.stringtable().s( dense.keys_vals( m_lastDenseTag ) ).data() );
470  QString value = QString::fromUtf8( m_primitiveBlock.stringtable().s( dense.keys_vals( m_lastDenseTag + 1 ) ).data() );
471 
472  if ( key == "name" ) {
473  node.name = value.trimmed();
474  } else if ( key == "addr:street" ) {
475  node.street = value.trimmed();
476  node.save = true;
477  } else if ( key == "addr:housenumber" ) {
478  node.houseNumber = value;
479  node.save = true;
480  } else if ( key == "addr:city" ) {
481  node.city = value;
482  node.save = true;
483  } else {
484  if ( shouldSave( Marble::NodeType, key, value ) ) {
485  node.save = true;
486  }
487  setCategory( node, key, value );
488  }
489 
490  m_lastDenseTag += 2;
491  }
492 
493  if ( node.save) {
494  m_nodes[m_lastDenseID] = node;
495  }
496 
497  if ( m_referencedNodes.contains( m_lastDenseID ) ) {
498  m_coordinates[m_lastDenseID] = node;
499  }
500  }
501 
502  ++m_currentEntity;
503  if ( m_currentEntity >= dense.id_size() ) {
504  m_currentEntity = 0;
505  m_currentGroup++;
506  if ( m_currentGroup >= m_primitiveBlock.primitivegroup_size() ) {
507  m_loadBlock = true;
508  } else {
509  loadGroup();
510  }
511  }
512 }
Marble::Relation::nodes
QList< int > nodes
Definition: tools/osm-addresses/OsmParser.h:123
Marble::OsmParser::m_coordinates
QHash< int, Coordinate > m_coordinates
Definition: tools/osm-addresses/OsmParser.h:167
PbfParser.h
Marble::OsmParser::setCategory
void setCategory(Element &element, const QString &key, const QString &value)
Definition: tools/osm-addresses/OsmParser.cpp:621
PbfParser::PbfParser
PbfParser()
Definition: PbfParser.cpp:28
Marble::Way::nodes
QList< int > nodes
Definition: tools/osm-addresses/OsmParser.h:80
Marble::Way
Definition: tools/osm-addresses/OsmParser.h:79
Marble::Relation::relations
QList< int > relations
Definition: tools/osm-addresses/OsmParser.h:125
PbfParser::parse
virtual bool parse(const QFileInfo &file, int pass, bool &needAnotherPass)
Definition: PbfParser.cpp:36
Marble::Relation::adminLevel
int adminLevel
Definition: tools/osm-addresses/OsmParser.h:129
Marble::Element::houseNumber
QString houseNumber
Definition: tools/osm-addresses/OsmParser.h:56
Marble::Node::lon
float lon
Definition: tools/osm-addresses/OsmParser.h:72
Marble::Relation
Definition: tools/osm-addresses/OsmParser.h:122
Marble::Outer
Definition: tools/osm-addresses/OsmParser.h:41
Marble::OsmParser::m_relations
QHash< int, Relation > m_relations
Definition: tools/osm-addresses/OsmParser.h:173
Marble::None
Definition: tools/osm-addresses/OsmParser.h:40
Marble::Relation::name
QString name
Definition: tools/osm-addresses/OsmParser.h:126
Marble::Relation::ways
QList< QPair< int, RelationRole > > ways
Definition: tools/osm-addresses/OsmParser.h:124
Marble::Element::street
QString street
Definition: tools/osm-addresses/OsmParser.h:55
Marble::NodeType
Definition: tools/osm-addresses/OsmParser.h:34
Marble::Node
Definition: tools/osm-addresses/OsmParser.h:71
Marble::WayType
Definition: tools/osm-addresses/OsmParser.h:35
Marble::OsmParser::shouldSave
bool shouldSave(ElementType type, const QString &key, const QString &value)
Definition: tools/osm-addresses/OsmParser.cpp:554
Marble::OsmParser::m_ways
QHash< int, Way > m_ways
Definition: tools/osm-addresses/OsmParser.h:171
Marble::Relation::isMultipolygon
bool isMultipolygon
Definition: tools/osm-addresses/OsmParser.h:127
Marble::Node::lat
float lat
Definition: tools/osm-addresses/OsmParser.h:73
Marble::Way::isBuilding
bool isBuilding
Definition: tools/osm-addresses/OsmParser.h:81
Marble::OsmParser::m_nodes
QHash< int, Node > m_nodes
Definition: tools/osm-addresses/OsmParser.h:169
Marble::Element::name
QString name
Definition: tools/osm-addresses/OsmParser.h:54
Marble::Inner
Definition: tools/osm-addresses/OsmParser.h:42
Marble::RelationRole
RelationRole
Definition: tools/osm-addresses/OsmParser.h:39
Marble::Relation::isAdministrativeBoundary
bool isAdministrativeBoundary
Definition: tools/osm-addresses/OsmParser.h:128
Marble::Element::city
QString city
Definition: tools/osm-addresses/OsmParser.h:57
Marble::Element::save
bool save
Definition: tools/osm-addresses/OsmParser.h:53
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:38:52 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

marble

Skip menu "marble"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal