File indexing completed on 2024-07-21 09:27:11

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