10#include "datasetmergebuffer.h"
19O5mParser::O5mParser(
DataSet *dataSet)
22 m_stringLookupTable.resize(O5M_STRING_TABLE_SIZE);
25void O5mParser::readFromData(
const uint8_t* data, std::size_t len)
27 std::fill(m_stringLookupTable.begin(), m_stringLookupTable.end(),
nullptr);
28 resetDeltaCodingState();
30 const auto endIt = data + len;
31 for (
auto it = data; it < endIt - 1;) {
32 const auto blockType = (*it);
33 if (blockType == O5M_BLOCK_RESET) {
34 resetDeltaCodingState();
39 auto blockSize = readUnsigned(++it, endIt);
40 if (blockSize >= (uint64_t)(endIt - it)) {
41 qWarning() <<
"premature end of file, or blocksize too large" << (endIt - it) << blockType << blockSize;
45 case O5M_BLOCK_HEADER:
46 if (blockSize != 4 || std::strncmp(
reinterpret_cast<const char*
>(it), O5M_HEADER, 4) != 0) {
47 qWarning() <<
"Invalid file header";
51 case O5M_BLOCK_BOUNDING_BOX:
52 case O5M_BLOCK_TIMESTAMP:
56 readNode(it, it + blockSize);
59 readWay(it, it + blockSize);
61 case O5M_BLOCK_RELATION:
62 readRelation(it, it + blockSize);
65 qDebug() <<
"unhandled o5m block type:" << (it - data) << blockType << blockSize;
72uint64_t O5mParser::readUnsigned(
const uint8_t *&it,
const uint8_t *endIt)
const
76 for (; it < endIt && ((*it) & O5M_NUMBER_CONTINUATION); ++it, ++i) {
77 result |= ((*it) & O5M_NUMBER_MASK) << (i * 7);
79 result |= ((uint64_t)(*it++) & O5M_NUMBER_MASK) << (i * 7);
83int64_t O5mParser::readSigned(
const uint8_t *&it,
const uint8_t *endIt)
const
85 const uint64_t u = readUnsigned(it, endIt);
86 return (u & O5M_NUMBER_SIGNED_BIT) ? (-(u >> 1) -1) : (u >> 1);
90T O5mParser::readDelta(
const uint8_t *&it,
const uint8_t *endIt, T &deltaState)
92 deltaState += (T)readSigned(it, endIt);
96const char* O5mParser::readString(
const uint8_t *&it,
const uint8_t *endIt)
98 auto ref = readUnsigned(it, endIt);
100 return m_stringLookupTable[(m_stringLookupPosition + O5M_STRING_TABLE_SIZE - ref) % O5M_STRING_TABLE_SIZE];
102 const auto s =
reinterpret_cast<const char*
>(it);
103 const auto len = std::strlen(s);
104 if (len <= O5M_STRING_TABLE_MAXLEN) {
105 m_stringLookupTable[m_stringLookupPosition] = s;
106 m_stringLookupPosition = (m_stringLookupPosition + 1) % O5M_STRING_TABLE_SIZE;
113std::pair<const char*, const char*> O5mParser::readStringPair(
const uint8_t *&it,
const uint8_t *endIt)
115 auto ref = readUnsigned(it, endIt);
117 const auto s = m_stringLookupTable[(m_stringLookupPosition + O5M_STRING_TABLE_SIZE - ref) % O5M_STRING_TABLE_SIZE];
121 const auto len1 = std::strlen(s);
122 return std::make_pair(s, s + len1 + 1);
124 const auto s =
reinterpret_cast<const char*
>(it);
125 const auto len1 = std::strlen(s);
126 const auto len2 = std::strlen(s + len1 + 1);
128 if (len1 + len2 <= O5M_STRING_TABLE_MAXLEN) {
129 m_stringLookupTable[m_stringLookupPosition] = s;
130 m_stringLookupPosition = (m_stringLookupPosition + 1) % O5M_STRING_TABLE_SIZE;
133 it += len1 + len2 + 2;
134 return std::make_pair(s, s + len1 + 1);
138void O5mParser::skipVersionInformation(
const uint8_t *&it,
const uint8_t *end)
140 if (it >= end) {
return; }
141 const auto version = readUnsigned(it, end);
143 qWarning() <<
"skipping changeset data not implemented yet!";
152template<
typename Elem>
153void O5mParser::readTagOrBbox(Elem &e,
const uint8_t *&it,
const uint8_t *endIt)
155 const auto tagData = readStringPair(it, endIt);
156 if (!tagData.first) {
159 if (std::strcmp(tagData.first,
"bBox") == 0) {
160 char *
next =
nullptr;
161 const auto lon1 = std::strtod(tagData.second, &next);
163 const auto lat1 = std::strtod(next, &next);
165 const auto lon2 = std::strtod(next, &next);
167 const auto lat2 = std::strtod(next, &next);
173 tag.key = m_dataSet->
makeTagKey(tagData.first, OSM::StringMemory::Transient);
175 e.tags.push_back(std::move(tag));
178void O5mParser::readNode(
const uint8_t *begin,
const uint8_t *end)
183 node.id = readDelta(it, end, m_nodeIdDelta);
184 skipVersionInformation(it, end);
185 if (it >= end) {
return; }
187 node.coordinate.longitude = (int64_t)readDelta(it, end, m_lonDelta) + 1'800'000'000ll;
188 node.coordinate.latitude = (int64_t)readDelta(it, end, m_latDelata) + 900'000'000ll;
192 const auto tagData = readStringPair(it, end);
194 tag.key = m_dataSet->
makeTagKey(tagData.first, OSM::StringMemory::Transient);
196 node.tags.push_back(std::move(tag));
199 std::sort(node.tags.begin(), node.tags.end());
204void O5mParser::readWay(
const uint8_t *begin,
const uint8_t *end)
209 way.id = readDelta(it, end, m_wayIdDelta);
210 skipVersionInformation(it, end);
211 if (it >= end) {
return; }
213 const auto nodesBlockSize = readUnsigned(it, end);
214 if (it + nodesBlockSize > end) {
return; }
216 const auto nodesBlockEnd = it + nodesBlockSize;
217 while(it < nodesBlockEnd) {
218 way.nodes.push_back(readDelta(it, end, m_wayNodeIdDelta));
222 readTagOrBbox(way, it, end);
224 std::sort(way.tags.begin(), way.tags.end());
226 addWay(std::move(way));
229void O5mParser::readRelation(
const uint8_t *begin,
const uint8_t *end)
234 rel.id = readDelta(it, end, m_relIdDelta);
235 skipVersionInformation(it, end);
236 if (it >= end) {
return; }
238 const auto relBlockSize = readUnsigned(it, end);
239 if (it + relBlockSize > end) {
return; }
241 const auto relBlockEnd = it + relBlockSize;
242 while (it < relBlockEnd) {
243 const int64_t memId = readSigned(it, end);
245 const auto typeAndRole = readString(it, end);
246 switch (typeAndRole[0]) {
247 case O5M_MEMTYPE_NODE:
248 mem.id = m_relNodeMemberIdDelta += memId;
249 mem.setType(OSM::Type::Node);
251 case O5M_MEMTYPE_WAY:
252 mem.id = m_relWayMemberIdDelta += memId;
253 mem.setType(OSM::Type::Way);
255 case O5M_MEMTYPE_RELATION:
256 mem.id = m_relRelMemberIdDelta += memId;
257 mem.setType(OSM::Type::Relation);
260 mem.setRole(m_dataSet->
makeRole(typeAndRole + 1, OSM::StringMemory::Transient));
262 rel.members.push_back(std::move(mem));
268 readTagOrBbox(rel, it, end);
270 std::sort(rel.tags.begin(), rel.tags.end());
272 addRelation(std::move(rel));
275void O5mParser::resetDeltaCodingState()
282 m_wayNodeIdDelta = 0;
285 m_relNodeMemberIdDelta = 0;
286 m_relWayMemberIdDelta = 0;
287 m_relRelMemberIdDelta = 0;
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.
Coordinate, stored as 1e7 * degree to avoid floating point precision issues, and offset to unsigned v...
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.
KDB_EXPORT KDbVersionInfo version()
const QList< QKeySequence > & begin()
const QList< QKeySequence > & next()
const QList< QKeySequence > & end()
Low-level types and functions to work with raw OSM data as efficiently as possible.
Common declarations for O5M file format I/O.