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 }