void OsmAnd::ObfRoutingSectionReader_P::readBorderLinePoints(
    const std::unique_ptr<ObfReader_P>& reader,
    QList< std::shared_ptr<const ObfRoutingBorderLinePoint> >* resultOut /*= nullptr*/,
    IQueryFilter* filter /*= nullptr*/,
    std::function<bool (const std::shared_ptr<const ObfRoutingBorderLinePoint>&)> visitor /*= nullptr*/
    )
{
    auto cis = reader->_codedInputStream.get();

    PointI location;
    gpb::uint64 id;

    for(;;)
    {
        auto tag = cis->ReadTag();
        switch(gpb::internal::WireFormatLite::GetTagFieldNumber(tag))
        {
        case 0:
            return;
        case OBF::OsmAndRoutingIndex_RouteBorderPointsBlock::kXFieldNumber:
            cis->ReadVarint32(reinterpret_cast<gpb::uint32*>(&location.x));
            break;
        case OBF::OsmAndRoutingIndex_RouteBorderPointsBlock::kYFieldNumber:
            cis->ReadVarint32(reinterpret_cast<gpb::uint32*>(&location.y));
            break;
        case OBF::OsmAndRoutingIndex_RouteBorderPointsBlock::kBaseIdFieldNumber:
            cis->ReadVarint64(&id);
            break;
        case OBF::OsmAndRoutingIndex_RouteBorderPointsBlock::kPointsFieldNumber:
            {
                gpb::uint32 length;
                cis->ReadVarint32(&length);
                auto oldLimit = cis->PushLimit(length);

                const std::shared_ptr<ObfRoutingBorderLinePoint> point(new ObfRoutingBorderLinePoint());
                readBorderLinePoint(reader, point);

                cis->PopLimit(oldLimit);

                point->_id += id;
                point->_location += location;
                id = point->_id;
                location = point->_location;

                bool valid = true;
                if(filter)
                    valid = filter->acceptsPoint(point->location);
                if(valid && visitor)
                    valid = visitor(point);
                if(valid && resultOut)
                    resultOut->push_back(qMove(point));
            }
            break;
        default:
            ObfReaderUtilities::skipUnknownField(cis, tag);
            break;
        }
    }
}
void OsmAnd::ObfAddressSectionReader_P::readStreet(
    const std::unique_ptr<ObfReader_P>& reader, const std::shared_ptr<const Model::StreetGroup>& group,
    const std::shared_ptr<Model::Street>& street)
{
    auto cis = reader->_codedInputStream.get();

    for(;;)
    {
        auto tag = cis->ReadTag();
        switch(gpb::internal::WireFormatLite::GetTagFieldNumber(tag))
        {
        case 0:
            if(street->_latinName.isEmpty())
                street->_latinName = reader->transliterate(street->_name);
            return;
        case OBF::StreetIndex::kIdFieldNumber:
            cis->ReadVarint64(reinterpret_cast<gpb::uint64*>(&street->_id));
            break;
        case OBF::StreetIndex::kNameEnFieldNumber:
            ObfReaderUtilities::readQString(cis, street->_latinName);
            break;
        case OBF::StreetIndex::kNameFieldNumber:
            ObfReaderUtilities::readQString(cis, street->_name);
            break;
        case OBF::StreetIndex::kXFieldNumber:
            {
                auto dx = ObfReaderUtilities::readSInt32(cis);
                street->_tile24.x = (Utilities::get31TileNumberX(group->_longitude) >> 7) + dx;
            }
            break;
        case OBF::StreetIndex::kYFieldNumber:
            {
                auto dy = ObfReaderUtilities::readSInt32(cis);
                street->_tile24.y = (Utilities::get31TileNumberY(group->_latitude) >> 7) + dy;
            }
            break;
        case OBF::StreetIndex::kIntersectionsFieldNumber:
        case OBF::StreetIndex::kBuildingsFieldNumber:
            {
                gpb::uint32 length;
                cis->ReadVarint32(&length);
                cis->Skip(length);
            }
            break;
        default:
            ObfReaderUtilities::skipUnknownField(cis, tag);
            break;
        }
    }
}
void OsmAnd::ObfRoutingSectionReader_P::readBorderLinePoint(
    const std::unique_ptr<ObfReader_P>& reader,
    const std::shared_ptr<ObfRoutingBorderLinePoint>& point)
{
    auto cis = reader->_codedInputStream.get();

    for(;;)
    {
        auto tag = cis->ReadTag();
        switch(gpb::internal::WireFormatLite::GetTagFieldNumber(tag))
        {
        case 0:
            return;
        case OBF::OsmAndRoutingIndex_RouteBorderPoint::kDxFieldNumber:
            cis->ReadVarint32(reinterpret_cast<gpb::uint32*>(&point->_location.x));
            break;
        case OBF::OsmAndRoutingIndex_RouteBorderPoint::kDyFieldNumber:
            cis->ReadVarint32(reinterpret_cast<gpb::uint32*>(&point->_location.y));
            break;
        case OBF::OsmAndRoutingIndex_RouteBorderPoint::kRoadIdFieldNumber:
            cis->ReadVarint64(&point->_id);
            break;
        case OBF::OsmAndRoutingIndex_RouteBorderPoint::kDirectionFieldNumber:
            {
                gpb::uint32 value;
                cis->ReadVarint32(&value);
                //TODO:p.direction = codedIS.readBool();
            }
            break;
        case OBF::OsmAndRoutingIndex_RouteBorderPoint::kTypesFieldNumber:
            {
                gpb::uint32 length;
                cis->ReadVarint32(&length);
                auto oldLimit = cis->PushLimit(length);
                while(cis->BytesUntilLimit() > 0)
                {
                    gpb::uint32 value;
                    cis->ReadVarint32(&value);
                    point->_types.push_back(value);
                }
                cis->PopLimit(oldLimit);
            }
            break;
        default:
            ObfReaderUtilities::skipUnknownField(cis, tag);
            break;
        }
    }
}
Beispiel #4
0
bool OsmAnd::ObfReader_P::readInfo(const ObfReader_P& reader, std::shared_ptr<const ObfInfo>& info_)
{
    auto cis = reader._codedInputStream.get();

    std::shared_ptr<ObfInfo> info(new ObfInfo());
    bool loadedCorrectly = false;
    for(;;)
    {
        auto tag = cis->ReadTag();
        switch(gpb::internal::WireFormatLite::GetTagFieldNumber(tag))
        {
        case 0:
            if(loadedCorrectly)
                info_ = info;

            return loadedCorrectly;
        case OBF::OsmAndStructure::kVersionFieldNumber:
            cis->ReadVarint32(reinterpret_cast<gpb::uint32*>(&info->_version));
            break;
        case OBF::OsmAndStructure::kDateCreatedFieldNumber:
            cis->ReadVarint64(reinterpret_cast<gpb::uint64*>(&info->_creationTimestamp));
            break;
        case OBF::OsmAndStructure::kMapIndexFieldNumber:
            {
                const std::shared_ptr<ObfMapSectionInfo> section(new ObfMapSectionInfo(info));
                section->_length = ObfReaderUtilities::readBigEndianInt(cis);
                section->_offset = cis->CurrentPosition();
                auto oldLimit = cis->PushLimit(section->_length);

                ObfMapSectionReader_P::read(reader, section);

                info->_isBasemap = info->_isBasemap || section->isBasemap;
                cis->PopLimit(oldLimit);
                cis->Seek(section->_offset + section->_length);

                info->_mapSections.push_back(qMove(section));
            }
            break;
        case OBF::OsmAndStructure::kAddressIndexFieldNumber:
            {
                const std::shared_ptr<ObfAddressSectionInfo> section(new ObfAddressSectionInfo(info));
                section->_length = ObfReaderUtilities::readBigEndianInt(cis);
                section->_offset = cis->CurrentPosition();
                auto oldLimit = cis->PushLimit(section->_length);

                ObfAddressSectionReader_P::read(reader, section);

                cis->PopLimit(oldLimit);
                cis->Seek(section->_offset + section->_length);

                info->_addressSections.push_back(qMove(section));
            }
            break;
        case OBF::OsmAndStructure::kTransportIndexFieldNumber:
            {
                const std::shared_ptr<ObfTransportSectionInfo> section(new ObfTransportSectionInfo(info));
                section->_length = ObfReaderUtilities::readBigEndianInt(cis);
                section->_offset = cis->CurrentPosition();
                auto oldLimit = cis->PushLimit(section->_length);

                ObfTransportSectionReader_P::read(reader, section);

                cis->PopLimit(oldLimit);
                cis->Seek(section->_offset + section->_length);

                info->_transportSections.push_back(qMove(section));
            }
            break;
        case OBF::OsmAndStructure::kRoutingIndexFieldNumber:
            {
                const std::shared_ptr<ObfRoutingSectionInfo> section(new ObfRoutingSectionInfo(info));
                section->_length = ObfReaderUtilities::readBigEndianInt(cis);
                section->_offset = cis->CurrentPosition();
                auto oldLimit = cis->PushLimit(section->_length);

                ObfRoutingSectionReader_P::read(reader, section);

                cis->PopLimit(oldLimit);
                cis->Seek(section->_offset + section->_length);

                info->_routingSections.push_back(qMove(section));
            }
            break;
        case OBF::OsmAndStructure::kPoiIndexFieldNumber:
            {
                const std::shared_ptr<ObfPoiSectionInfo> section(new ObfPoiSectionInfo(info));
                section->_length = ObfReaderUtilities::readBigEndianInt(cis);
                section->_offset = cis->CurrentPosition();
                auto oldLimit = cis->PushLimit(section->_length);

                ObfPoiSectionReader_P::read(reader, section);

                cis->PopLimit(oldLimit);
                cis->Seek(section->_offset + section->_length);

                info->_poiSections.push_back(qMove(section));
            }
            break;
        case OBF::OsmAndStructure::kVersionConfirmFieldNumber:
            {
                gpb::uint32 controlVersion;
                cis->ReadVarint32(&controlVersion);
                loadedCorrectly = (controlVersion == info->_version);
                if(!loadedCorrectly)
                    break;
            }
            break;
        default:
            ObfReaderUtilities::skipUnknownField(cis, tag);
            break;
        }
    }

    return false;
}
void OsmAnd::ObfMapSectionReader_P::readMapObjectsBlock(
    const ObfReader_P& reader,
    const std::shared_ptr<const ObfMapSectionInfo>& section,
    const std::shared_ptr<const ObfMapSectionLevelTreeNode>& tree,
    QList< std::shared_ptr<const OsmAnd::BinaryMapObject> >* resultOut,
    const AreaI* bbox31,
    const FilterReadingByIdFunction filterById,
    const VisitorFunction visitor,
    const std::shared_ptr<const IQueryController>& queryController,
    ObfMapSectionReader_Metrics::Metric_loadMapObjects* const metric)
{
    const auto cis = reader.getCodedInputStream().get();

    QList< std::shared_ptr<BinaryMapObject> > intermediateResult;
    QStringList mapObjectsCaptionsTable;
    gpb::uint64 baseId = 0;
    for (;;)
    {
        const auto tag = cis->ReadTag();
        switch (gpb::internal::WireFormatLite::GetTagFieldNumber(tag))
        {
            case 0:
            {
                if (!ObfReaderUtilities::reachedDataEnd(cis))
                    return;

                for (const auto& mapObject : constOf(intermediateResult))
                {
                    // Fill mapObject captions from string-table
                    for (auto& caption : mapObject->captions)
                    {
                        const auto stringId = ObfReaderUtilities::decodeIntegerFromString(caption);

                        if (stringId >= mapObjectsCaptionsTable.size())
                        {
                            LogPrintf(LogSeverityLevel::Error,
                                "Data mismatch: string #%d (map object %s not found in string table (size %d) in section '%s'",
                                stringId,
                                qPrintable(mapObject->id.toString()),
                                mapObjectsCaptionsTable.size(), qPrintable(section->name));
                            caption = QString::fromLatin1("#%1 NOT FOUND").arg(stringId);
                            continue;
                        }
                        caption = mapObjectsCaptionsTable[stringId];
                    }

                    //////////////////////////////////////////////////////////////////////////
                    //if (mapObject->id.getOsmId() == 49048972u)
                    //{
                    //    int i = 5;
                    //}
                    //////////////////////////////////////////////////////////////////////////

                    if (!visitor || visitor(mapObject))
                    {
                        if (resultOut)
                            resultOut->push_back(qMove(mapObject));
                    }
                }

                return;
            }
            case OBF::MapDataBlock::kBaseIdFieldNumber:
            {
                cis->ReadVarint64(&baseId);
                //////////////////////////////////////////////////////////////////////////
                //if (bbox31)
                //    LogPrintf(LogSeverityLevel::Debug, "BBOX %d %d %d %d - MAP BLOCK %" PRIi64, bbox31->top, bbox31->left, bbox31->bottom, bbox31->right, baseId);
                //////////////////////////////////////////////////////////////////////////
                break;
            }
            case OBF::MapDataBlock::kDataObjectsFieldNumber:
            {
                gpb::uint32 length;
                cis->ReadVarint32(&length);
                const auto offset = cis->CurrentPosition();

                // Read map object content
                const Stopwatch readMapObjectStopwatch(metric != nullptr);
                std::shared_ptr<OsmAnd::BinaryMapObject> mapObject;
                auto oldLimit = cis->PushLimit(length);
                
                readMapObject(reader, section, baseId, tree, mapObject, bbox31, metric);

                ObfReaderUtilities::ensureAllDataWasRead(cis);
                cis->PopLimit(oldLimit);

                // Update metric
                if (metric)
                    metric->visitedMapObjects++;

                // If map object was not read, skip it
                if (!mapObject)
                {
                    if (metric)
                        metric->elapsedTimeForOnlyVisitedMapObjects += readMapObjectStopwatch.elapsed();

                    break;
                }

                // Update metric
                if (metric)
                {
                    metric->elapsedTimeForOnlyAcceptedMapObjects += readMapObjectStopwatch.elapsed();

                    metric->acceptedMapObjects++;
                }

                //////////////////////////////////////////////////////////////////////////
                //if (mapObject->id.getOsmId() == 49048972u)
                //{
                //    int i = 5;
                //}
                //////////////////////////////////////////////////////////////////////////

                // Check if map object is desired
                const auto shouldReject = filterById && !filterById(
                    section,
                    mapObject->id,
                    mapObject->bbox31,
                    mapObject->level->minZoom,
                    mapObject->level->maxZoom);
                if (shouldReject)
                    break;

                // Save object
                intermediateResult.push_back(qMove(mapObject));

                break;
            }
            case OBF::MapDataBlock::kStringTableFieldNumber:
            {
                gpb::uint32 length;
                cis->ReadVarint32(&length);
                const auto offset = cis->CurrentPosition();
                auto oldLimit = cis->PushLimit(length);
                if (intermediateResult.isEmpty())
                {
                    cis->Skip(cis->BytesUntilLimit());
                    cis->PopLimit(oldLimit);
                    break;
                }
                
                ObfReaderUtilities::readStringTable(cis, mapObjectsCaptionsTable);

                ObfReaderUtilities::ensureAllDataWasRead(cis);
                cis->PopLimit(oldLimit);

                break;
            }
            default:
                ObfReaderUtilities::skipUnknownField(cis, tag);
                break;
        }
    }
}
void OsmAnd::ObfAddressSectionReader_P::readBuilding(
    const std::unique_ptr<ObfReader_P>& reader, const std::shared_ptr<const Model::Street>& street,
    const std::shared_ptr<Model::Building>& building )
{
    auto cis = reader->_codedInputStream.get();

    for(;;)
    {
        auto tag = cis->ReadTag();
        switch(gpb::internal::WireFormatLite::GetTagFieldNumber(tag))
        {
        case 0:
            if(building->_latinName.isEmpty())
                building->_latinName = reader->transliterate(building->_name);
            if(building->_latinName2.isEmpty())
                building->_latinName2 = reader->transliterate(building->_name2);
            return;
        case OBF::BuildingIndex::kIdFieldNumber:
            cis->ReadVarint64(reinterpret_cast<gpb::uint64*>(&building->_id));
            break;
        case OBF::BuildingIndex::kNameEnFieldNumber:
            ObfReaderUtilities::readQString(cis, building->_latinName);
            break;
        case OBF::BuildingIndex::kNameFieldNumber:
            ObfReaderUtilities::readQString(cis, building->_name);
            break;
        case OBF::BuildingIndex::kNameEn2FieldNumber:
            ObfReaderUtilities::readQString(cis, building->_latinName2);
            break;
        case OBF::BuildingIndex::kName2FieldNumber:
            ObfReaderUtilities::readQString(cis, building->_name2);
            break;
        case OBF::BuildingIndex::kInterpolationFieldNumber:
            {
                auto value = ObfReaderUtilities::readSInt32(cis);
                if(value > 0)
                    building->_interpolationInterval = value;
                else
                    building->_interpolation = static_cast<Model::Building::Interpolation>(value);
            }
            break;
        case OBF::BuildingIndex::kXFieldNumber:
            {
                auto dx = ObfReaderUtilities::readSInt32(cis);
                building->_xTile24 = street->_tile24.x + dx;
            }
            break;
        case OBF::BuildingIndex::kX2FieldNumber:
            {
                auto dx2 = ObfReaderUtilities::readSInt32(cis);
                building->_x2Tile24 = street->_tile24.x + dx2;
            }
            break;
        case OBF::BuildingIndex::kYFieldNumber:
            {
                auto dy = ObfReaderUtilities::readSInt32(cis);
                building->_yTile24 = street->_tile24.y + dy;
            }
            break;
        case OBF::BuildingIndex::kY2FieldNumber:
            {
                auto dy2 = ObfReaderUtilities::readSInt32(cis);
                building->_y2Tile24 = street->_tile24.y + dy2;
            }
            break;
        case OBF::BuildingIndex::kPostcodeFieldNumber:
            ObfReaderUtilities::readQString(cis, building->_postcode);
            break;
        default:
            ObfReaderUtilities::skipUnknownField(cis, tag);
            break;
        }
    }
}
void OsmAnd::ObfAddressSectionReader_P::readStreetGroupHeader(
    const std::unique_ptr<ObfReader_P>& reader, const std::shared_ptr<const ObfAddressBlocksSectionInfo>& section,
    unsigned int offset, std::shared_ptr<OsmAnd::Model::StreetGroup>& outStreetGroup )
{
    auto cis = reader->_codedInputStream.get();

    std::shared_ptr<OsmAnd::Model::StreetGroup> streetGroup;
    //    boolean englishNameMatched = false;
    for(;;)
    {
        auto tag = cis->ReadTag();
        switch(gpb::internal::WireFormatLite::GetTagFieldNumber(tag))
        {
        case 0:
            if(streetGroup->_latinName.isEmpty())
                streetGroup->_latinName = reader->transliterate(streetGroup->_name);
            outStreetGroup = streetGroup;
            return;
        case OBF::CityIndex::kCityTypeFieldNumber:
            {
                gpb::uint32 type;
                cis->ReadVarint32(&type);
                streetGroup.reset(new Model::Settlement(/*TODO:type*/));
            }
            break;
        case OBF::CityIndex::kIdFieldNumber:
            cis->ReadVarint64(reinterpret_cast<gpb::uint64*>(&streetGroup->_id));
            /*
            TODO:
            if(nameMatcher != null && useEn && !englishNameMatched){
            codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
            return null;
            }
            */
            break;
        case OBF::CityIndex::kNameEnFieldNumber:
            {
                ObfReaderUtilities::readQString(cis, streetGroup->_latinName);
                /*
                TODO:
                if (nameMatcher != null && latinName.length() > 0 && nameMatcher.matches(latinName)) {
                englishNameMatched = true;
                }
                */
            }
            break;
        case OBF::CityIndex::kNameFieldNumber:
            {
                QString name;
                ObfReaderUtilities::readQString(cis, name);
                /*
                if(nameMatcher != null){
                if(!useEn){
                if(!nameMatcher.matches(name)) {
                codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
                return null;
                }
                } else if(nameMatcher.matches(Junidecode.unidecode(name))){
                englishNameMatched = true;
                }
                }
                */

                if(!streetGroup)
                    streetGroup.reset(new Model::PostcodeArea());

                streetGroup->_name = name;
            }
            break;
        case OBF::CityIndex::kXFieldNumber:
            {
                gpb::uint32 x = 0;
                cis->ReadVarint32(&x);
                streetGroup->_longitude = Utilities::get31LongitudeX(x);
            }
            break;
        case OBF::CityIndex::kYFieldNumber:
            {
                gpb::uint32 y = 0;
                cis->ReadVarint32(&y);
                streetGroup->_latitude = Utilities::get31LatitudeY(y);
            }
            break;
        case OBF::CityIndex::kShiftToCityBlockIndexFieldNumber:
            streetGroup->_offset = ObfReaderUtilities::readBigEndianInt(cis) + offset;
            break;
        default:
            ObfReaderUtilities::skipUnknownField(cis, tag);
            break;
        }
    }
}
void OsmAnd::ObfMapSectionReader_P::readMapObjectsBlock(
    const std::unique_ptr<ObfReader_P>& reader, const std::shared_ptr<const ObfMapSectionInfo>& section,
    const std::shared_ptr<ObfMapSectionLevelTreeNode>& tree,
    QList< std::shared_ptr<const OsmAnd::Model::MapObject> >* resultOut,
    const AreaI* bbox31,
    const FilterMapObjectsByIdSignature filterById,
    std::function<bool (const std::shared_ptr<const OsmAnd::Model::MapObject>&)> visitor,
    const IQueryController* const controller,
    ObfMapSectionReader_Metrics::Metric_loadMapObjects* const metric)
{
    auto cis = reader->_codedInputStream.get();

    QList< std::shared_ptr<Model::MapObject> > intermediateResult;
    QStringList mapObjectsNamesTable;
    gpb::uint64 baseId = 0;
    for(;;)
    {
        if(controller && controller->isAborted())
            return;
        
        auto tag = cis->ReadTag();
        switch(gpb::internal::WireFormatLite::GetTagFieldNumber(tag))
        {
        case 0:
            for(const auto& mapObject : constOf(intermediateResult))
            {
                // Fill mapObject names from stringtable
                for(auto& nameValue : mapObject->_names)
                {
                    const auto stringId = ObfReaderUtilities::decodeIntegerFromString(nameValue);

                    if(stringId >= mapObjectsNamesTable.size())
                    {
                        LogPrintf(LogSeverityLevel::Error,
                            "Data mismatch: string #%d (map object #%" PRIu64 " (%" PRIi64 ") not found in string table (size %d) in section '%s'",
                            stringId,
                            mapObject->id >> 1, static_cast<int64_t>(mapObject->id) / 2,
                            mapObjectsNamesTable.size(), qPrintable(section->name));
                        nameValue = QString::fromLatin1("#%1 NOT FOUND").arg(stringId);
                        continue;
                    }
                    nameValue = mapObjectsNamesTable[stringId];
                }

                if(!visitor || visitor(mapObject))
                {
                    if(resultOut)
                        resultOut->push_back(qMove(mapObject));
                }
            }
            return;
        case OBF::MapDataBlock::kBaseIdFieldNumber:
            cis->ReadVarint64(&baseId);
            break;
        case OBF::MapDataBlock::kDataObjectsFieldNumber:
            {
                gpb::uint32 length;
                cis->ReadVarint32(&length);

                // Update metric
                std::chrono::high_resolution_clock::time_point readMapObject_begin;
                if(metric)
                    readMapObject_begin = std::chrono::high_resolution_clock::now();

                // Read map object content
                std::shared_ptr<OsmAnd::Model::MapObject> mapObject;
                {
                    auto oldLimit = cis->PushLimit(length);

                    readMapObject(reader, section, baseId, tree, mapObject, bbox31);
                    assert(cis->BytesUntilLimit() == 0);

                    // Update metric
                    if(metric)
                        metric->visitedMapObjects++;

                    cis->PopLimit(oldLimit);
                }

                // If map object was not read, skip it
                if(!mapObject)
                {
                    // Update metric
                    if(metric)
                    {
                        const std::chrono::duration<float> readMapObject_elapsed = std::chrono::high_resolution_clock::now() - readMapObject_begin;
                        metric->elapsedTimeForOnlyVisitedMapObjects += readMapObject_elapsed.count();
                    }

                    break;
                }

                // Update metric
                if(metric)
                {
                    const std::chrono::duration<float> readMapObject_elapsed = std::chrono::high_resolution_clock::now() - readMapObject_begin;
                    metric->elapsedTimeForOnlyAcceptedMapObjects += readMapObject_elapsed.count();

                    metric->acceptedMapObjects++;
                }

                // Make unique map object identifier
                mapObject->_id = Model::MapObject::getUniqueId(mapObject->_id, section);

                // Check if map object is desired
                if(filterById && !filterById(section, mapObject->id, mapObject->bbox31, mapObject->level->minZoom, mapObject->level->maxZoom))
                    break;

                // Save object
                mapObject->_foundation = tree->_foundation;
                intermediateResult.push_back(qMove(mapObject));
            }
            break;
        case OBF::MapDataBlock::kStringTableFieldNumber:
            {
                gpb::uint32 length;
                cis->ReadVarint32(&length);
                auto oldLimit = cis->PushLimit(length);
                if(intermediateResult.isEmpty())
                {
                    cis->Skip(cis->BytesUntilLimit());
                    cis->PopLimit(oldLimit);
                    break;
                }
                ObfReaderUtilities::readStringTable(cis, mapObjectsNamesTable);
                assert(cis->BytesUntilLimit() == 0);
                cis->PopLimit(oldLimit);
            }
            break;
        default:
            ObfReaderUtilities::skipUnknownField(cis, tag);
            break;
        }
    }
void OsmAnd::ObfMapSectionReader_P::readMapObjectsBlock(
    const std::unique_ptr<ObfReader_P>& reader, const std::shared_ptr<const ObfMapSectionInfo>& section,
    const std::shared_ptr<ObfMapSectionLevelTreeNode>& tree,
    QList< std::shared_ptr<const OsmAnd::Model::MapObject> >* resultOut,
    const AreaI* bbox31,
    std::function<bool (const std::shared_ptr<const OsmAnd::Model::MapObject>&)> visitor,
    IQueryController* controller)
{
    auto cis = reader->_codedInputStream.get();

    QList< std::shared_ptr<OsmAnd::Model::MapObject> > intermediateResult;
    QStringList mapObjectsNamesTable;
    gpb::uint64 baseId = 0;
    for(;;)
    {
        if(controller && controller->isAborted())
            return;
        
        auto tag = cis->ReadTag();
        switch(gpb::internal::WireFormatLite::GetTagFieldNumber(tag))
        {
        case 0:
            for(auto itEntry = intermediateResult.begin(); itEntry != intermediateResult.end(); ++itEntry)
            {
                const auto& entry = *itEntry;

                // Fill names of roads from stringtable
                for(auto itNameEntry = entry->_names.begin(); itNameEntry != entry->_names.end(); ++itNameEntry)
                {
                    const auto& encodedId = itNameEntry.value();
                    uint32_t stringId = 0;
                    stringId |= (encodedId.at(1 + 0).unicode() & 0xff) << 8*0;
                    stringId |= (encodedId.at(1 + 1).unicode() & 0xff) << 8*1;
                    stringId |= (encodedId.at(1 + 2).unicode() & 0xff) << 8*2;
                    stringId |= (encodedId.at(1 + 3).unicode() & 0xff) << 8*3;

                    if(stringId >= mapObjectsNamesTable.size())
                    {
                        LogPrintf(LogSeverityLevel::Error,
                            "Data mismatch: string #%d (map object #%" PRIu64 " (%" PRIi64 ") not found in string table(%d) in section '%s'",
                            stringId,
                            entry->id >> 1, static_cast<int64_t>(entry->id) / 2,
                            mapObjectsNamesTable.size(), qPrintable(section->name));
                        itNameEntry.value() = QString::fromLatin1("#%1 NOT FOUND").arg(stringId);
                        continue;
                    }
                    itNameEntry.value() = mapObjectsNamesTable[stringId];
                }

                if(!visitor || visitor(entry))
                {
                    if(resultOut)
                        resultOut->push_back(entry);
                }
            }
            return;
        case OBF::MapDataBlock::kBaseIdFieldNumber:
            cis->ReadVarint64(&baseId);
            break;
        case OBF::MapDataBlock::kDataObjectsFieldNumber:
            {
                gpb::uint32 length;
                cis->ReadVarint32(&length);
                auto oldLimit = cis->PushLimit(length);
                auto pos = cis->CurrentPosition();
                std::shared_ptr<OsmAnd::Model::MapObject> mapObject;
                readMapObject(reader, section, tree, baseId, mapObject, bbox31);
                if(mapObject)
                {
                    mapObject->_foundation = tree->_foundation;
                    intermediateResult.push_back(mapObject);
                }
                cis->PopLimit(oldLimit);
            }
            break;
        case OBF::MapDataBlock::kStringTableFieldNumber:
            {
                gpb::uint32 length;
                cis->ReadVarint32(&length);
                auto oldLimit = cis->PushLimit(length);
                if(intermediateResult.isEmpty())
                {
                    cis->Skip(cis->BytesUntilLimit());
                    cis->PopLimit(oldLimit);
                    break;
                }
                ObfReaderUtilities::readStringTable(cis, mapObjectsNamesTable);
                cis->PopLimit(oldLimit);
            }
            break;
        default:
            ObfReaderUtilities::skipUnknownField(cis, tag);
            break;
        }
    }