KOSMIndoorMap

osmpbfparser.cpp
1 /*
2  SPDX-FileCopyrightText: 2020 Volker Krause <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "config-kosm.h"
8 #include "osmpbfparser.h"
9 
10 #ifdef HAVE_PROTOBUF
11 #include "fileformat.pb.h"
12 #include "osmformat.pb.h"
13 
14 #include <zlib.h>
15 #endif
16 
17 #include <QByteArray>
18 #include <QDebug>
19 #include <QtEndian>
20 
21 
22 using namespace OSM;
23 
24 OsmPbfParser::OsmPbfParser(DataSet *dataSet)
25  : m_dataSet(dataSet)
26 {
27 }
28 
29 void OsmPbfParser::parse(const uint8_t *data, std::size_t len)
30 {
31 #ifdef HAVE_PROTOBUF
32  const uint8_t *it = data;
33  const uint8_t *end = data + len;
34  while (parseBlob(it, end));
35 #else
36  Q_UNUSED(data);
37  Q_UNUSED(len);
38  qWarning() << "OSM PBF file format not available!";
39  return;
40 #endif
41 }
42 
43 #ifdef HAVE_PROTOBUF
44 bool OsmPbfParser::parseBlob(const uint8_t *&it, const uint8_t *end)
45 {
46  if (std::distance(it, end) < (int)sizeof(int32_t)) {
47  return false;
48  }
49  int32_t blobHeaderSize = 0;
50  std::memcpy(&blobHeaderSize, it, sizeof(int32_t));
51  blobHeaderSize = qFromBigEndian(blobHeaderSize);
52  it += sizeof(int32_t);
53 
54  if (blobHeaderSize < 0 || std::distance(it, end) < blobHeaderSize) {
55  return false;
56  }
57 
58  OSMPBF::BlobHeader blobHeader;
59  if (!blobHeader.ParseFromArray(it, blobHeaderSize)) {
60  return false;
61  }
62  it += blobHeaderSize;
63 
64  OSMPBF::Blob blob;
65  if (std::distance(it, end) < blobHeader.datasize() || !blob.ParseFromArray(it, blobHeader.datasize())) {
66  return false;
67  }
68 
69  const uint8_t *dataBegin = nullptr;
70  if (blob.has_raw()) {
71  dataBegin = reinterpret_cast<const uint8_t*>(blob.raw().data());
72  } else if (blob.has_zlib_data()) {
73  m_zlibBuffer.resize(blob.raw_size());
74  z_stream zStream;
75  zStream.next_in = (uint8_t*)blob.zlib_data().data();
76  zStream.avail_in = blob.zlib_data().size();
77  zStream.next_out = (uint8_t*)m_zlibBuffer.data();
78  zStream.avail_out = blob.raw_size();
79  zStream.zalloc = nullptr;
80  zStream.zfree = nullptr;
81  zStream.opaque = nullptr;
82  auto result = inflateInit(&zStream);
83  if (result != Z_OK) {
84  return false;
85  }
86  result = inflate(&zStream, Z_FINISH);
87  if (result != Z_STREAM_END) {
88  return false;
89  }
90  result = inflateEnd( &zStream );
91  dataBegin = reinterpret_cast<const uint8_t*>(m_zlibBuffer.constData());
92  } else {
93  return false;
94  }
95  if (std::strcmp(blobHeader.type().c_str(), "OSMData") == 0) {
96  parsePrimitiveBlock(dataBegin, blob.raw_size());
97  }
98 
99  m_zlibBuffer.clear();
100  it += blobHeader.datasize();
101  return true;
102 }
103 
104 void OsmPbfParser::parsePrimitiveBlock(const uint8_t *data, std::size_t len)
105 {
106  OSMPBF::PrimitiveBlock block;
107  if (!block.ParseFromArray(data, len)) {
108  return;
109  }
110 
111  for (int i = 0; i < block.primitivegroup_size(); ++i) {
112  const auto &group = block.primitivegroup(i);
113 
114  if (group.nodes_size()) {
115  qWarning() << "non-dense nodes - not implemented yet!";
116  } else if (group.has_dense()) {
117  parseDenseNodes(block, group);
118  } else if (group.ways_size()) {
119  parseWays(block, group);
120  } else if (group.relations_size()) {
121  parseRelations(block, group);
122  }
123  }
124 }
125 
126 void OsmPbfParser::parseDenseNodes(const OSMPBF::PrimitiveBlock &block, const OSMPBF::PrimitiveGroup &group)
127 {
128  int64_t idDelta = 0;
129  int64_t latDelta = 0;
130  int64_t lonDelta = 0;
131  int tagIdx = 0;
132 
133  const auto dense = group.dense();
134  for (int i = 0; i < dense.id_size(); ++i) {
135  idDelta += dense.id(i);
136  latDelta += dense.lat(i);
137  lonDelta += dense.lon(i);
138 
139  OSM::Node node;
140  node.id = idDelta;
141  node.coordinate.latitude = latDelta + 900'000'000ll;
142  node.coordinate.longitude = lonDelta + 1'800'000'000ll;
143 
144  while (tagIdx < dense.keys_vals_size()) {
145  const auto keyIdx = dense.keys_vals(tagIdx++);
146  if (keyIdx == 0) {
147  break;
148  }
149  const auto valIdx = dense.keys_vals(tagIdx++);
150 
151  OSM::Tag tag;
152  tag.key = m_dataSet->makeTagKey(block.stringtable().s(keyIdx).data());
153  tag.value = QByteArray(block.stringtable().s(valIdx).data());
154  OSM::setTag(node, std::move(tag));
155  }
156 
157  m_dataSet->addNode(std::move(node));
158  }
159 }
160 
161 void OsmPbfParser::parseWays(const OSMPBF::PrimitiveBlock &block, const OSMPBF::PrimitiveGroup &group)
162 {
163  for (int i = 0; i < group.ways_size(); ++i) {
164  const auto &w = group.ways(i);
165 
166  OSM::Way way;
167  way.id = w.id();
168  way.nodes.reserve(w.refs_size());
169 
170  int64_t idDelta = 0;
171  for (int j = 0; j < w.refs_size(); ++j) {
172  idDelta += w.refs(j);
173  way.nodes.push_back(idDelta);
174  }
175 
176  for (int j = 0; j < w.keys_size(); ++j) {
177  OSM::Tag tag;
178  tag.key = m_dataSet->makeTagKey(block.stringtable().s(w.keys(j)).data());
179  tag.value = QByteArray(block.stringtable().s(w.vals(j)).data());
180  OSM::setTag(way, std::move(tag));
181  }
182 
183  m_dataSet->addWay(std::move(way));
184  }
185 }
186 
187 void OsmPbfParser::parseRelations(const OSMPBF::PrimitiveBlock &block, const OSMPBF::PrimitiveGroup &group)
188 {
189  for (int i = 0; i < group.relations_size(); ++i) {
190  const auto &r = group.relations(i);
191 
192  OSM::Relation rel;
193  rel.id = r.id();
194  rel.members.reserve(r.memids_size());
195 
196  int64_t idDelta = 0;
197  for (int j = 0; j < r.memids_size(); ++j) {
198  OSM::Member mem;
199 
200  idDelta += r.memids(j);
201  mem.id = idDelta;
202  mem.setRole(m_dataSet->makeRole(block.stringtable().s(r.roles_sid(j)).data()));
203  const auto type = r.types(j);
204  switch (type) {
205  case OSMPBF::Relation_MemberType_NODE: mem.setType(OSM::Type::Node); break;
206  case OSMPBF::Relation_MemberType_WAY: mem.setType(OSM::Type::Way); break;
207  case OSMPBF::Relation_MemberType_RELATION: mem.setType(OSM::Type::Relation); break;
208  }
209 
210  rel.members.push_back(std::move(mem));
211  }
212 
213  for (int j = 0; j < r.keys_size(); ++j) {
214  OSM::Tag tag;
215  tag.key = m_dataSet->makeTagKey(block.stringtable().s(r.keys(j)).data());
216  tag.value = QByteArray(block.stringtable().s(r.vals(j)).data());
217  OSM::setTag(rel, std::move(tag));
218  }
219 
220  m_dataSet->addRelation(std::move(rel));
221  }
222 }
223 
224 #endif
An OSM node.
Definition: datatypes.h:194
A set of nodes, ways and relations.
Definition: datatypes.h:283
Low-level types and functions to work with raw OSM data as efficiently as possible.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Oct 25 2021 23:04:00 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.