File indexing completed on 2024-05-05 04:42:57
0001 /* 0002 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "osmpbfparser.h" 0008 0009 #include "fileformat.pb.h" 0010 #include "osmformat.pb.h" 0011 0012 #include <zlib.h> 0013 0014 #include <QByteArray> 0015 #include <QDebug> 0016 #include <QtEndian> 0017 0018 using namespace OSM; 0019 0020 OsmPbfParser::OsmPbfParser(DataSet *dataSet) 0021 : AbstractReader(dataSet) 0022 { 0023 } 0024 0025 void OsmPbfParser::readFromData(const uint8_t *data, std::size_t len) 0026 { 0027 const uint8_t *it = data; 0028 const uint8_t *end = data + len; 0029 while (parseBlob(it, end)); 0030 } 0031 0032 bool OsmPbfParser::parseBlob(const uint8_t *&it, const uint8_t *end) 0033 { 0034 if (std::distance(it, end) < (int)sizeof(int32_t)) { 0035 return false; 0036 } 0037 int32_t blobHeaderSize = 0; 0038 std::memcpy(&blobHeaderSize, it, sizeof(int32_t)); 0039 blobHeaderSize = qFromBigEndian(blobHeaderSize); 0040 it += sizeof(int32_t); 0041 0042 if (blobHeaderSize < 0 || std::distance(it, end) < blobHeaderSize) { 0043 return false; 0044 } 0045 0046 OSMPBF::BlobHeader blobHeader; 0047 if (!blobHeader.ParseFromArray(it, blobHeaderSize)) { 0048 return false; 0049 } 0050 it += blobHeaderSize; 0051 0052 OSMPBF::Blob blob; 0053 if (std::distance(it, end) < blobHeader.datasize() || !blob.ParseFromArray(it, blobHeader.datasize())) { 0054 return false; 0055 } 0056 0057 const uint8_t *dataBegin = nullptr; 0058 if (blob.has_raw()) { 0059 dataBegin = reinterpret_cast<const uint8_t*>(blob.raw().data()); 0060 } else if (blob.has_zlib_data()) { 0061 m_zlibBuffer.resize(blob.raw_size()); 0062 z_stream zStream; 0063 zStream.next_in = (uint8_t*)blob.zlib_data().data(); 0064 zStream.avail_in = blob.zlib_data().size(); 0065 zStream.next_out = (uint8_t*)m_zlibBuffer.data(); 0066 zStream.avail_out = blob.raw_size(); 0067 zStream.zalloc = nullptr; 0068 zStream.zfree = nullptr; 0069 zStream.opaque = nullptr; 0070 auto result = inflateInit(&zStream); 0071 if (result != Z_OK) { 0072 return false; 0073 } 0074 result = inflate(&zStream, Z_FINISH); 0075 if (result != Z_STREAM_END) { 0076 return false; 0077 } 0078 result = inflateEnd( &zStream ); 0079 dataBegin = reinterpret_cast<const uint8_t*>(m_zlibBuffer.constData()); 0080 } else { 0081 return false; 0082 } 0083 if (std::strcmp(blobHeader.type().c_str(), "OSMData") == 0) { 0084 parsePrimitiveBlock(dataBegin, blob.raw_size()); 0085 } 0086 0087 m_zlibBuffer.clear(); 0088 it += blobHeader.datasize(); 0089 return true; 0090 } 0091 0092 void OsmPbfParser::parsePrimitiveBlock(const uint8_t *data, std::size_t len) 0093 { 0094 OSMPBF::PrimitiveBlock block; 0095 if (!block.ParseFromArray(data, len)) { 0096 return; 0097 } 0098 0099 for (int i = 0; i < block.primitivegroup_size(); ++i) { 0100 const auto &group = block.primitivegroup(i); 0101 0102 if (group.nodes_size()) { 0103 qWarning() << "non-dense nodes - not implemented yet!"; 0104 } else if (group.has_dense()) { 0105 parseDenseNodes(block, group); 0106 } else if (group.ways_size()) { 0107 parseWays(block, group); 0108 } else if (group.relations_size()) { 0109 parseRelations(block, group); 0110 } 0111 } 0112 } 0113 0114 void OsmPbfParser::parseDenseNodes(const OSMPBF::PrimitiveBlock &block, const OSMPBF::PrimitiveGroup &group) 0115 { 0116 int64_t idDelta = 0; 0117 int64_t latDelta = 0; 0118 int64_t lonDelta = 0; 0119 int tagIdx = 0; 0120 0121 const auto dense = group.dense(); 0122 for (int i = 0; i < dense.id_size(); ++i) { 0123 idDelta += dense.id(i); 0124 latDelta += dense.lat(i); 0125 lonDelta += dense.lon(i); 0126 0127 OSM::Node node; 0128 node.id = idDelta; 0129 node.coordinate.latitude = latDelta + 900'000'000ll; 0130 node.coordinate.longitude = lonDelta + 1'800'000'000ll; 0131 0132 while (tagIdx < dense.keys_vals_size()) { 0133 const auto keyIdx = dense.keys_vals(tagIdx++); 0134 if (keyIdx == 0) { 0135 break; 0136 } 0137 const auto valIdx = dense.keys_vals(tagIdx++); 0138 0139 OSM::Tag tag; 0140 tag.key = m_dataSet->makeTagKey(block.stringtable().s(keyIdx).data()); 0141 tag.value = QByteArray(block.stringtable().s(valIdx).data()); 0142 OSM::setTag(node, std::move(tag)); 0143 } 0144 0145 addNode(std::move(node)); 0146 } 0147 } 0148 0149 void OsmPbfParser::parseWays(const OSMPBF::PrimitiveBlock &block, const OSMPBF::PrimitiveGroup &group) 0150 { 0151 for (int i = 0; i < group.ways_size(); ++i) { 0152 const auto &w = group.ways(i); 0153 0154 OSM::Way way; 0155 way.id = w.id(); 0156 way.nodes.reserve(w.refs_size()); 0157 0158 int64_t idDelta = 0; 0159 for (int j = 0; j < w.refs_size(); ++j) { 0160 idDelta += w.refs(j); 0161 way.nodes.push_back(idDelta); 0162 } 0163 0164 for (int j = 0; j < w.keys_size(); ++j) { 0165 OSM::Tag tag; 0166 tag.key = m_dataSet->makeTagKey(block.stringtable().s(w.keys(j)).data()); 0167 tag.value = QByteArray(block.stringtable().s(w.vals(j)).data()); 0168 OSM::setTag(way, std::move(tag)); 0169 } 0170 0171 addWay(std::move(way)); 0172 } 0173 } 0174 0175 void OsmPbfParser::parseRelations(const OSMPBF::PrimitiveBlock &block, const OSMPBF::PrimitiveGroup &group) 0176 { 0177 for (int i = 0; i < group.relations_size(); ++i) { 0178 const auto &r = group.relations(i); 0179 0180 OSM::Relation rel; 0181 rel.id = r.id(); 0182 rel.members.reserve(r.memids_size()); 0183 0184 int64_t idDelta = 0; 0185 for (int j = 0; j < r.memids_size(); ++j) { 0186 OSM::Member mem; 0187 0188 idDelta += r.memids(j); 0189 mem.id = idDelta; 0190 mem.setRole(m_dataSet->makeRole(block.stringtable().s(r.roles_sid(j)).data())); 0191 const auto type = r.types(j); 0192 switch (type) { 0193 case OSMPBF::Relation_MemberType_NODE: mem.setType(OSM::Type::Node); break; 0194 case OSMPBF::Relation_MemberType_WAY: mem.setType(OSM::Type::Way); break; 0195 case OSMPBF::Relation_MemberType_RELATION: mem.setType(OSM::Type::Relation); break; 0196 } 0197 0198 rel.members.push_back(std::move(mem)); 0199 } 0200 0201 for (int j = 0; j < r.keys_size(); ++j) { 0202 OSM::Tag tag; 0203 tag.key = m_dataSet->makeTagKey(block.stringtable().s(r.keys(j)).data()); 0204 tag.value = QByteArray(block.stringtable().s(r.vals(j)).data()); 0205 OSM::setTag(rel, std::move(tag)); 0206 } 0207 0208 addRelation(std::move(rel)); 0209 } 0210 }