7#include "osmpbfparser.h"
9#include "fileformat.pb.h"
10#include "osmformat.pb.h"
20OsmPbfParser::OsmPbfParser(
DataSet *dataSet)
25void OsmPbfParser::readFromData(
const uint8_t *data, std::size_t len)
27 const uint8_t *it = data;
28 const uint8_t *
end = data + len;
29 while (parseBlob(it, end));
32bool OsmPbfParser::parseBlob(
const uint8_t *&it,
const uint8_t *end)
34 if (std::distance(it, end) < (
int)
sizeof(int32_t)) {
37 int32_t blobHeaderSize = 0;
38 std::memcpy(&blobHeaderSize, it,
sizeof(int32_t));
39 blobHeaderSize = qFromBigEndian(blobHeaderSize);
40 it +=
sizeof(int32_t);
42 if (blobHeaderSize < 0 || std::distance(it, end) < blobHeaderSize) {
46 OSMPBF::BlobHeader blobHeader;
47 if (!blobHeader.ParseFromArray(it, blobHeaderSize)) {
53 if (std::distance(it, end) < blobHeader.datasize() || !blob.ParseFromArray(it, blobHeader.datasize())) {
57 const uint8_t *dataBegin =
nullptr;
59 dataBegin =
reinterpret_cast<const uint8_t*
>(blob.raw().data());
60 }
else if (blob.has_zlib_data()) {
61 m_zlibBuffer.
resize(blob.raw_size());
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);
74 result = inflate(&zStream, Z_FINISH);
75 if (result != Z_STREAM_END) {
78 result = inflateEnd( &zStream );
79 dataBegin =
reinterpret_cast<const uint8_t*
>(m_zlibBuffer.
constData());
83 if (std::strcmp(blobHeader.type().c_str(),
"OSMData") == 0) {
84 parsePrimitiveBlock(dataBegin, blob.raw_size());
88 it += blobHeader.datasize();
92void OsmPbfParser::parsePrimitiveBlock(
const uint8_t *data, std::size_t len)
94 OSMPBF::PrimitiveBlock block;
95 if (!block.ParseFromArray(data, len)) {
99 for (
int i = 0; i < block.primitivegroup_size(); ++i) {
100 const auto &group = block.primitivegroup(i);
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);
114void OsmPbfParser::parseDenseNodes(
const OSMPBF::PrimitiveBlock &block,
const OSMPBF::PrimitiveGroup &group)
117 int64_t latDelta = 0;
118 int64_t lonDelta = 0;
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);
129 node.coordinate.latitude = latDelta + 900'000'000ll;
130 node.coordinate.longitude = lonDelta + 1'800'000'000ll;
132 while (tagIdx < dense.keys_vals_size()) {
133 const auto keyIdx = dense.keys_vals(tagIdx++);
137 const auto valIdx = dense.keys_vals(tagIdx++);
140 tag.key = m_dataSet->
makeTagKey(block.stringtable().s(keyIdx).data());
141 tag.value =
QByteArray(block.stringtable().s(valIdx).data());
149void OsmPbfParser::parseWays(
const OSMPBF::PrimitiveBlock &block,
const OSMPBF::PrimitiveGroup &group)
151 for (
int i = 0; i < group.ways_size(); ++i) {
152 const auto &w = group.ways(i);
156 way.nodes.reserve(w.refs_size());
159 for (
int j = 0; j < w.refs_size(); ++j) {
160 idDelta += w.refs(j);
161 way.nodes.push_back(idDelta);
164 for (
int j = 0; j < w.keys_size(); ++j) {
166 tag.key = m_dataSet->
makeTagKey(block.stringtable().s(w.keys(j)).data());
167 tag.value =
QByteArray(block.stringtable().s(w.vals(j)).data());
171 addWay(std::move(way));
175void OsmPbfParser::parseRelations(
const OSMPBF::PrimitiveBlock &block,
const OSMPBF::PrimitiveGroup &group)
177 for (
int i = 0; i < group.relations_size(); ++i) {
178 const auto &r = group.relations(i);
182 rel.members.reserve(r.memids_size());
185 for (
int j = 0; j < r.memids_size(); ++j) {
188 idDelta += r.memids(j);
190 mem.setRole(m_dataSet->
makeRole(block.stringtable().s(r.roles_sid(j)).data()));
191 const auto type = r.types(j);
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;
198 rel.members.push_back(std::move(mem));
201 for (
int j = 0; j < r.keys_size(); ++j) {
203 tag.key = m_dataSet->
makeTagKey(block.stringtable().s(r.keys(j)).data());
204 tag.value =
QByteArray(block.stringtable().s(r.vals(j)).data());
208 addRelation(std::move(rel));
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.
TagKey makeTagKey(const char *keyName, StringMemory keyMemOpt=StringMemory::Transient)
Create a tag key for the given tag name.
Role makeRole(const char *roleName, StringMemory memOpt=StringMemory::Transient)
Creates a role name key.
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
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.
const char * constData() const const
void resize(qsizetype newSize, char c)