KOSMIndoorMap

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

KDE's Doxygen guidelines are available online.