void OsmAnd::ObfMapSectionReader_P::readMapObject( const ObfReader_P& reader, const std::shared_ptr<const ObfMapSectionInfo>& section, uint64_t baseId, const std::shared_ptr<const ObfMapSectionLevelTreeNode>& treeNode, std::shared_ptr<OsmAnd::BinaryMapObject>& mapObject, const AreaI* bbox31, ObfMapSectionReader_Metrics::Metric_loadMapObjects* const metric) { const auto cis = reader.getCodedInputStream().get(); const auto baseOffset = cis->CurrentPosition(); for (;;) { const auto tag = cis->ReadTag(); const auto tgn = gpb::internal::WireFormatLite::GetTagFieldNumber(tag); switch (tgn) { case 0: { if (!ObfReaderUtilities::reachedDataEnd(cis)) return; if (mapObject && mapObject->points31.isEmpty()) { LogPrintf(LogSeverityLevel::Warning, "Empty BinaryMapObject %s detected in section '%s'", qPrintable(mapObject->id.toString()), qPrintable(section->name)); mapObject.reset(); } return; } case OBF::MapData::kAreaCoordinatesFieldNumber: case OBF::MapData::kCoordinatesFieldNumber: { const Stopwatch mapObjectPointsStopwatch(metric != nullptr); gpb::uint32 length; cis->ReadVarint32(&length); const auto oldLimit = cis->PushLimit(length); PointI p; p.x = treeNode->area31.left() & MaskToRead; p.y = treeNode->area31.top() & MaskToRead; AreaI objectBBox; objectBBox.top() = objectBBox.left() = std::numeric_limits<int32_t>::max(); objectBBox.bottom() = objectBBox.right() = 0; auto lastUnprocessedVertexForBBox = 0; // In protobuf, a sint32 can be encoded using [1..4] bytes, // so try to guess size of array, and preallocate it. // (BytesUntilLimit/2) is ~= number of vertices, and is always larger than needed. // So it's impossible that a buffer overflow will ever happen. But assert on that. const auto probableVerticesCount = (cis->BytesUntilLimit() / 2); QVector< PointI > points31(probableVerticesCount); auto pPoint = points31.data(); auto verticesCount = 0; bool shouldNotSkip = (bbox31 == nullptr); while (cis->BytesUntilLimit() > 0) { PointI d; d.x = (ObfReaderUtilities::readSInt32(cis) << ShiftCoordinates); d.y = (ObfReaderUtilities::readSInt32(cis) << ShiftCoordinates); p += d; // Save point into storage assert(points31.size() > verticesCount); *(pPoint++) = p; verticesCount++; // Check if map object should be maintained if (!shouldNotSkip && bbox31) { const Stopwatch mapObjectBboxStopwatch(metric != nullptr); shouldNotSkip = bbox31->contains(p); objectBBox.enlargeToInclude(p); if (metric) metric->elapsedTimeForMapObjectsBbox += mapObjectBboxStopwatch.elapsed(); lastUnprocessedVertexForBBox = verticesCount; } } cis->PopLimit(oldLimit); // Since reserved space may be larger than actual amount of data, // shrink the vertices array points31.resize(verticesCount); // If map object has no vertices, retain it in a special way to report later, when // it's identifier will be known if (points31.isEmpty()) { // Fake that this object is inside bbox shouldNotSkip = true; objectBBox = treeNode->area31; } // Even if no vertex lays inside bbox, an edge // may intersect the bbox if (!shouldNotSkip && bbox31) { assert(lastUnprocessedVertexForBBox == points31.size()); shouldNotSkip = objectBBox.contains(*bbox31) || bbox31->intersects(objectBBox); } // If map object didn't fit, skip it's entire content if (!shouldNotSkip) { if (metric) { metric->elapsedTimeForSkippedMapObjectsPoints += mapObjectPointsStopwatch.elapsed(); metric->skippedMapObjectsPoints += points31.size(); } cis->Skip(cis->BytesUntilLimit()); break; } // Update metric if (metric) { metric->elapsedTimeForNotSkippedMapObjectsPoints += mapObjectPointsStopwatch.elapsed(); metric->notSkippedMapObjectsPoints += points31.size(); } // In case bbox is not fully calculated, complete this task auto pPointForBBox = points31.data() + lastUnprocessedVertexForBBox; while (lastUnprocessedVertexForBBox < points31.size()) { const Stopwatch mapObjectBboxStopwatch(metric != nullptr); objectBBox.enlargeToInclude(*pPointForBBox); if (metric) metric->elapsedTimeForMapObjectsBbox += mapObjectBboxStopwatch.elapsed(); lastUnprocessedVertexForBBox++; pPointForBBox++; } // Finally, create the object if (!mapObject) mapObject.reset(new OsmAnd::BinaryMapObject(section, treeNode->level)); mapObject->isArea = (tgn == OBF::MapData::kAreaCoordinatesFieldNumber); mapObject->points31 = qMove(points31); mapObject->bbox31 = objectBBox; assert(treeNode->area31.top() - mapObject->bbox31.top() <= 32); assert(treeNode->area31.left() - mapObject->bbox31.left() <= 32); assert(mapObject->bbox31.bottom() - treeNode->area31.bottom() <= 1); assert(mapObject->bbox31.right() - treeNode->area31.right() <= 1); assert(mapObject->bbox31.right() >= mapObject->bbox31.left()); assert(mapObject->bbox31.bottom() >= mapObject->bbox31.top()); break; } case OBF::MapData::kPolygonInnerCoordinatesFieldNumber: { if (!mapObject) mapObject.reset(new OsmAnd::BinaryMapObject(section, treeNode->level)); gpb::uint32 length; cis->ReadVarint32(&length); auto oldLimit = cis->PushLimit(length); PointI p; p.x = treeNode->area31.left() & MaskToRead; p.y = treeNode->area31.top() & MaskToRead; // Preallocate memory const auto probableVerticesCount = (cis->BytesUntilLimit() / 2); mapObject->innerPolygonsPoints31.push_back(qMove(QVector< PointI >(probableVerticesCount))); auto& polygon = mapObject->innerPolygonsPoints31.last(); auto pPoint = polygon.data(); auto verticesCount = 0; while (cis->BytesUntilLimit() > 0) { PointI d; d.x = (ObfReaderUtilities::readSInt32(cis) << ShiftCoordinates); d.y = (ObfReaderUtilities::readSInt32(cis) << ShiftCoordinates); p += d; // Save point into storage assert(polygon.size() > verticesCount); *(pPoint++) = p; verticesCount++; } // Shrink memory polygon.resize(verticesCount); cis->PopLimit(oldLimit); break; } case OBF::MapData::kAdditionalTypesFieldNumber: case OBF::MapData::kTypesFieldNumber: { if (!mapObject) mapObject.reset(new OsmAnd::BinaryMapObject(section, treeNode->level)); auto& attributeIds = (tgn == OBF::MapData::kAdditionalTypesFieldNumber) ? mapObject->additionalAttributeIds : mapObject->attributeIds; gpb::uint32 length; cis->ReadVarint32(&length); auto oldLimit = cis->PushLimit(length); // Preallocate space attributeIds.reserve(cis->BytesUntilLimit()); while (cis->BytesUntilLimit() > 0) { gpb::uint32 attributeId; cis->ReadVarint32(&attributeId); attributeIds.push_back(attributeId); } // Shrink preallocated space attributeIds.squeeze(); cis->PopLimit(oldLimit); break; } case OBF::MapData::kStringNamesFieldNumber: { gpb::uint32 length; cis->ReadVarint32(&length); auto oldLimit = cis->PushLimit(length); while (cis->BytesUntilLimit() > 0) { bool ok; gpb::uint32 stringRuleId; ok = cis->ReadVarint32(&stringRuleId); assert(ok); gpb::uint32 stringId; ok = cis->ReadVarint32(&stringId); assert(ok); mapObject->captions.insert(stringRuleId, qMove(ObfReaderUtilities::encodeIntegerToString(stringId))); mapObject->captionsOrder.push_back(stringRuleId); } cis->PopLimit(oldLimit); break; } case OBF::MapData::kIdFieldNumber: { const auto d = ObfReaderUtilities::readSInt64(cis); const auto rawId = static_cast<uint64_t>(d + baseId); mapObject->id = ObfObjectId::generateUniqueId(rawId, baseOffset, section); ////////////////////////////////////////////////////////////////////////// //if (mapObject->id.getOsmId() == 49048972u) //{ // int i = 5; //} ////////////////////////////////////////////////////////////////////////// break; } default: ObfReaderUtilities::skipUnknownField(cis, tag); break; } } }
void OsmAnd::ObfMapSectionReader_P::readTreeNode( const ObfReader_P& reader, const std::shared_ptr<const ObfMapSectionInfo>& section, const AreaI& parentArea, const std::shared_ptr<ObfMapSectionLevelTreeNode>& treeNode) { const auto cis = reader.getCodedInputStream().get(); uint64_t fieldsMask = 0u; const auto safeToSkipFieldsMask = (1ull << OBF::OsmAndMapIndex_MapDataBox::kLeftFieldNumber) | (1ull << OBF::OsmAndMapIndex_MapDataBox::kRightFieldNumber) | (1ull << OBF::OsmAndMapIndex_MapDataBox::kTopFieldNumber) | (1ull << OBF::OsmAndMapIndex_MapDataBox::kBottomFieldNumber); bool kBoxesFieldNumberProcessed = false; for (;;) { const auto tagPos = cis->CurrentPosition(); const auto tag = cis->ReadTag(); const auto tfn = gpb::internal::WireFormatLite::GetTagFieldNumber(tag); switch (tfn) { case 0: if (!ObfReaderUtilities::reachedDataEnd(cis)) return; return; case OBF::OsmAndMapIndex_MapDataBox::kLeftFieldNumber: { const auto d = ObfReaderUtilities::readSInt32(cis); treeNode->area31.left() = d + parentArea.left(); fieldsMask |= (1ull << tfn); break; } case OBF::OsmAndMapIndex_MapDataBox::kRightFieldNumber: { const auto d = ObfReaderUtilities::readSInt32(cis); treeNode->area31.right() = d + parentArea.right(); fieldsMask |= (1ull << tfn); break; } case OBF::OsmAndMapIndex_MapDataBox::kTopFieldNumber: { const auto d = ObfReaderUtilities::readSInt32(cis); treeNode->area31.top() = d + parentArea.top(); fieldsMask |= (1ull << tfn); break; } case OBF::OsmAndMapIndex_MapDataBox::kBottomFieldNumber: { const auto d = ObfReaderUtilities::readSInt32(cis); treeNode->area31.bottom() = d + parentArea.bottom(); fieldsMask |= (1ull << tfn); break; } case OBF::OsmAndMapIndex_MapDataBox::kShiftToMapDataFieldNumber: { const auto offset = ObfReaderUtilities::readBigEndianInt(cis); treeNode->dataOffset = offset + treeNode->offset; fieldsMask |= (1ull << tfn); break; } case OBF::OsmAndMapIndex_MapDataBox::kOceanFieldNumber: { gpb::uint32 value; cis->ReadVarint32(&value); treeNode->surfaceType = (value != 0) ? MapSurfaceType::FullWater : MapSurfaceType::FullLand; assert( (treeNode->surfaceType != MapSurfaceType::FullWater) || (treeNode->surfaceType == MapSurfaceType::FullWater && section->isBasemapWithCoastlines)); fieldsMask |= (1ull << tfn); break; } case OBF::OsmAndMapIndex_MapDataBox::kBoxesFieldNumber: { if (!kBoxesFieldNumberProcessed) { treeNode->hasChildrenDataBoxes = true; treeNode->firstDataBoxInnerOffset = tagPos - treeNode->offset; kBoxesFieldNumberProcessed = true; if (fieldsMask == safeToSkipFieldsMask) { cis->Skip(cis->BytesUntilLimit()); return; } } ObfReaderUtilities::skipUnknownField(cis, tag); fieldsMask |= (1ull << tfn); break; } default: ObfReaderUtilities::skipUnknownField(cis, tag); break; } } }