File indexing completed on 2025-01-05 03:59:29
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 #ifdef HAVE_PROTOBUF 0010 # include "fileformat.pb.h" 0011 # include "osmformat.pb.h" 0012 #endif 0013 0014 #include <QDebug> 0015 #include <QtEndian> 0016 0017 #include <zlib.h> 0018 0019 #include <cstdint> 0020 #include <cstring> 0021 0022 #include <klocalizedstring.h> 0023 0024 using namespace Marble; 0025 0026 void OsmPbfParser::parse(const uint8_t *data, std::size_t len) 0027 { 0028 #ifdef HAVE_PROTOBUF 0029 const uint8_t *it = data; 0030 const uint8_t *end = data + len; 0031 while (parseBlob(it, end)); 0032 #else 0033 Q_UNUSED(data); 0034 Q_UNUSED(len); 0035 #endif 0036 } 0037 0038 #ifdef HAVE_PROTOBUF 0039 bool OsmPbfParser::parseBlob(const uint8_t *&it, const uint8_t *end) 0040 { 0041 if (std::distance(it, end) < (int)sizeof(int32_t)) { 0042 return false; 0043 } 0044 int32_t blobHeaderSize = 0; 0045 std::memcpy(&blobHeaderSize, it, sizeof(int32_t)); 0046 blobHeaderSize = qFromBigEndian(blobHeaderSize); 0047 it += sizeof(int32_t); 0048 0049 if (blobHeaderSize < 0 || std::distance(it, end) < blobHeaderSize) { 0050 return false; 0051 } 0052 0053 OSMPBF::BlobHeader blobHeader; 0054 if (!blobHeader.ParseFromArray(it, blobHeaderSize)) { 0055 return false; 0056 } 0057 it += blobHeaderSize; 0058 0059 OSMPBF::Blob blob; 0060 if (std::distance(it, end) < blobHeader.datasize() || !blob.ParseFromArray(it, blobHeader.datasize())) { 0061 return false; 0062 } 0063 0064 const uint8_t *dataBegin = nullptr; 0065 if (blob.has_raw()) { 0066 dataBegin = reinterpret_cast<const uint8_t*>(blob.raw().data()); 0067 } else if (blob.has_zlib_data()) { 0068 m_zlibBuffer.resize(blob.raw_size()); 0069 z_stream zStream; 0070 zStream.next_in = (uint8_t*)blob.zlib_data().data(); 0071 zStream.avail_in = blob.zlib_data().size(); 0072 zStream.next_out = (uint8_t*)m_zlibBuffer.data(); 0073 zStream.avail_out = blob.raw_size(); 0074 zStream.zalloc = nullptr; 0075 zStream.zfree = nullptr; 0076 zStream.opaque = nullptr; 0077 auto result = inflateInit(&zStream); 0078 if (result != Z_OK) { 0079 return false; 0080 } 0081 result = inflate(&zStream, Z_FINISH); 0082 if (result != Z_STREAM_END) { 0083 return false; 0084 } 0085 result = inflateEnd( &zStream ); 0086 dataBegin = reinterpret_cast<const uint8_t*>(m_zlibBuffer.constData()); 0087 } else { 0088 return false; 0089 } 0090 if (std::strcmp(blobHeader.type().c_str(), "OSMData") == 0) { 0091 parsePrimitiveBlock(dataBegin, blob.raw_size()); 0092 } 0093 0094 m_zlibBuffer.clear(); 0095 it += blobHeader.datasize(); 0096 return true; 0097 } 0098 0099 void OsmPbfParser::parsePrimitiveBlock(const uint8_t *data, std::size_t len) 0100 { 0101 OSMPBF::PrimitiveBlock block; 0102 if (!block.ParseFromArray(data, len)) { 0103 return; 0104 } 0105 0106 for (int i = 0; i < block.primitivegroup_size(); ++i) { 0107 const auto &group = block.primitivegroup(i); 0108 0109 if (group.nodes_size()) { 0110 qCWarning(DIGIKAM_MARBLE_LOG) << QString::fromUtf8() << "non-dense nodes - not implemented yet!"; 0111 } else if (group.has_dense()) { 0112 parseDenseNodes(block, group); 0113 } else if (group.ways_size()) { 0114 parseWays(block, group); 0115 } else if (group.relations_size()) { 0116 parseRelations(block, group); 0117 } 0118 } 0119 } 0120 0121 void OsmPbfParser::parseDenseNodes(const OSMPBF::PrimitiveBlock &block, const OSMPBF::PrimitiveGroup &group) 0122 { 0123 int64_t idDelta = 0; 0124 int64_t latDelta = 0; 0125 int64_t lonDelta = 0; 0126 int tagIdx = 0; 0127 0128 const auto dense = group.dense(); 0129 for (int i = 0; i < dense.id_size(); ++i) { 0130 idDelta += dense.id(i); 0131 latDelta += dense.lat(i); 0132 lonDelta += dense.lon(i); 0133 0134 auto &node = m_nodes[idDelta]; 0135 node.osmData().setId(idDelta); 0136 node.setCoordinates(GeoDataCoordinates(lonDelta * 1.0e-7, latDelta * 1.0e-7, 0.0, GeoDataCoordinates::Degree)); 0137 0138 while (tagIdx < dense.keys_vals_size()) { 0139 const auto keyIdx = dense.keys_vals(tagIdx++); 0140 if (keyIdx == 0) { 0141 break; 0142 } 0143 const auto valIdx = dense.keys_vals(tagIdx++); 0144 const QString keyString = *m_stringPool.insert(QString::fromUtf8(block.stringtable().s(keyIdx).data())); 0145 const QString valueString = *m_stringPool.insert(QString::fromUtf8(block.stringtable().s(valIdx).data())); 0146 node.osmData().addTag(keyString, valueString); 0147 } 0148 } 0149 } 0150 0151 void OsmPbfParser::parseWays(const OSMPBF::PrimitiveBlock &block, const OSMPBF::PrimitiveGroup &group) 0152 { 0153 for (int i = 0; i < group.ways_size(); ++i) { 0154 const auto &w = group.ways(i); 0155 auto &way = m_ways[w.id()]; 0156 way.osmData().setId(w.id()); 0157 0158 int64_t idDelta = 0; 0159 for (int j = 0; j < w.refs_size(); ++j) { 0160 idDelta += w.refs(j); 0161 way.addReference(idDelta); 0162 } 0163 0164 for (int j = 0; j < w.keys_size(); ++j) { 0165 const QString keyString = *m_stringPool.insert(QString::fromUtf8(block.stringtable().s(w.keys(j)).data())); 0166 const QString valueString = *m_stringPool.insert(QString::fromUtf8(block.stringtable().s(w.vals(j)).data())); 0167 way.osmData().addTag(keyString, valueString); 0168 } 0169 } 0170 } 0171 0172 void OsmPbfParser::parseRelations(const OSMPBF::PrimitiveBlock &block, const OSMPBF::PrimitiveGroup &group) 0173 { 0174 for (int i = 0; i < group.relations_size(); ++i) { 0175 const auto &r = group.relations(i); 0176 0177 auto &rel = m_relations[r.id()]; 0178 rel.osmData().setId(r.id()); 0179 0180 int64_t idDelta = 0; 0181 for (int j = 0; j < r.memids_size(); ++j) { 0182 idDelta += r.memids(j); 0183 const QString role = *m_stringPool.insert(QString::fromUtf8(block.stringtable().s(r.roles_sid(j)).data())); 0184 QString typeName; 0185 const auto type = r.types(j); 0186 switch (type) { 0187 case OSMPBF::Relation_MemberType_NODE: typeName = QStringLiteral("node"); break; 0188 case OSMPBF::Relation_MemberType_WAY: typeName = QStringLiteral("way"); break; 0189 case OSMPBF::Relation_MemberType_RELATION: typeName = QStringLiteral("relation"); break; 0190 } 0191 rel.addMember(idDelta, role, typeName); 0192 } 0193 0194 for (int j = 0; j < r.keys_size(); ++j) { 0195 const QString keyString = *m_stringPool.insert(QString::fromUtf8(block.stringtable().s(r.keys(j)).data())); 0196 const QString valueString = *m_stringPool.insert(QString::fromUtf8(block.stringtable().s(r.vals(j)).data())); 0197 rel.osmData().addTag(keyString, valueString); 0198 } 0199 } 0200 } 0201 0202 #endif