Open OSM pbf results in Protobuf exception

馋奶兔 提交于 2020-01-15 03:16:07

问题


Using OSMSharp I am having trouble to open a stream for a file (which I can provide on demand)

The error occurs in PBFReader (line 104)

using (var tmp = new LimitedStream(_stream, length))
{
  header = _runtimeTypeModel.Deserialize(tmp, null, _blockHeaderType) as BlobHeader;
}

and states: "ProtoBuf.ProtoException: 'Invalid field in source data: 0'" which might mean different things as I have read in this SO question.

The file opens and is visualized with QGis so is not corrupt in my opinion.

Can it be that the contracts do not match? Is OsmSharp/core updated to the latest .proto files for OSM from here (although not sure if this is the real original source for the definition files).

And what might make more sense, can it be that the file I attached is generated for v2 of OSM PBF specification?

In the code at the line of the exception I see the following comment which makes me wonder:

// TODO: remove some of the v1 specific code.
// TODO: this means also to use the built-in capped streams.

// code borrowed from: http://stackoverflow.com/questions/4663298/protobuf-net-deserialize-open-street-maps

// I'm just being lazy and re-using something "close enough" here
// note that v2 has a big-endian option, but Fixed32 assumes little-endian - we
// actually need the other way around (network byte order):
// length = IntLittleEndianToBigEndian((uint)length);

BlobHeader header;
// again, v2 has capped-streams built in, but I'm deliberately
// limiting myself to v1 features

So this makes me wonder if OSM Sharp is (still) up-to-date.

My sandbox code looks like this:

using OsmSharp.Streams;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OsmSharp.Tags;

namespace OsmSharp
{
    class Program
    {
        private const string Path = @"C:\Users\Bernoulli IT\Documents\Applications\Argaleo\Test\";
        private const string FileNameAntarctica = "antarctica-latest.osm";
        private const string FileNameOSPbf = "OSPbf";
        private const Boolean useRegisterSource = false;
        private static KeyValuePair<string, string> KeyValuePair = new KeyValuePair<string, string>("joep", "monita");

        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            //string fileName = $@"{Path}\{FileNameAntarctica}.pbf";
            string fileName = $@"{Path}\{FileNameOSPbf}.pbf";

            string newFileName = $"{fileName.Replace(".pbf", string.Empty)}-{Guid.NewGuid().ToString().Substring(0, 4)}.pbf";


            Console.WriteLine("*** Complete");
            string fileNameOutput = CompleteFlow(fileName, newFileName);

            Console.WriteLine("");
            Console.WriteLine("*** Display");
            DisplayFlow(fileNameOutput);

            Console.ReadLine();
        }

        private static string CompleteFlow(string fileName, string newFileName)
        {
            // 1. Open file and convert to bytes
            byte[] fileBytes = FileToBytes(fileName);

            // 2. Bytes to OSM stream source (pbf)
            PBFOsmStreamSource osmStreamSource;

            osmStreamSource = BytesToOsmStreamSource(fileBytes);

            osmStreamSource.MoveNext();

            if (osmStreamSource.Current() == null)
            {
                osmStreamSource = FileToOsmStreamSource(fileName);

                osmStreamSource.MoveNext();

                if (osmStreamSource.Current() == null)
                {
                    throw new Exception("No current in stream.");
                }
            }

            // 3. Add custom tag
            AddTag(osmStreamSource);

            // 4. OSM stream source to bytes
            //byte[] osmStreamSourceBytes = OsmStreamSourceToBytes(osmStreamSource);

            // 5. Bytes to file
            //string fileNameOutput = BytesToFile(osmStreamSourceBytes, newFileName);

            OsmStreamSourceToFile(osmStreamSource, newFileName);

            Console.WriteLine(newFileName);

            return newFileName;
        }

        private static void DisplayFlow(string fileName)
        {
            // 1. Open file and convert to bytes
            byte[] fileBytes = FileToBytes(fileName);

            // 2. Bytes to OSM stream source (pbf)
            BytesToOsmStreamSource(fileBytes);
        }

        private static byte[] FileToBytes(string fileName)
        {
            Console.WriteLine(fileName);

            return File.ReadAllBytes(fileName);
        }

        private static PBFOsmStreamSource BytesToOsmStreamSource(byte[] bytes)
        {
            MemoryStream memoryStream = new MemoryStream(bytes);

            memoryStream.Position = 0;

            PBFOsmStreamSource osmStreamSource = new PBFOsmStreamSource(memoryStream);

            foreach (OsmGeo element in osmStreamSource.Where(osmGeo => osmGeo.Tags.Any(tag => tag.Key.StartsWith(KeyValuePair.Key))))
            {
                foreach (Tag elementTag in element.Tags.Where(tag => tag.Key.StartsWith(KeyValuePair.Key)))
                {
                    Console.WriteLine("!!!!!!!!!!!!!!      Tag found while reading           !!!!!!!!!!!!!!!!!!".ToUpper());
                }
            }

            return osmStreamSource;

        }

        private static PBFOsmStreamSource FileToOsmStreamSource(string fileName)
        {
            using (FileStream fileStream = new FileInfo(fileName).OpenRead())
            {
                PBFOsmStreamSource osmStreamSource = new PBFOsmStreamSource(fileStream);

                return osmStreamSource;
            }
        }

        private static void AddTag(PBFOsmStreamSource osmStreamSource)
        {
            osmStreamSource.Reset();

            OsmGeo osmGeo = null;

            while (osmGeo == null)
            {
                osmStreamSource.MoveNext();

                osmGeo = osmStreamSource.Current();

                if(osmGeo?.Tags == null)
                {
                    osmGeo = null;
                }
            }

            osmGeo.Tags.Add("joep", "monita");

            Console.WriteLine($"{osmGeo.Tags.FirstOrDefault(tag => tag.Key.StartsWith(KeyValuePair.Key)).Key} - {osmGeo.Tags.FirstOrDefault(tag => tag.Key.StartsWith(KeyValuePair.Key)).Value}");
        }

        private static byte[] OsmStreamSourceToBytes(PBFOsmStreamSource osmStreamSource)
        {
            MemoryStream memoryStream = new MemoryStream();

            PBFOsmStreamTarget target = new PBFOsmStreamTarget(memoryStream, true);

            osmStreamSource.Reset();

            target.Initialize();

            UpdateTarget(osmStreamSource, target);

            target.Flush();

            target.Close();

            return memoryStream.ToArray();
        }

        private static string BytesToFile(byte[] bytes, string fileName)
        {
            using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
            {
                fs.Write(bytes, 0, bytes.Length);
            }

            return fileName;
        }

        private static void OsmStreamSourceToFile(PBFOsmStreamSource osmStreamSource, string fileName)
        {
            using (FileStream fileStream = new FileInfo(fileName).OpenWrite())
            {
                PBFOsmStreamTarget target = new PBFOsmStreamTarget(fileStream, true);

                osmStreamSource.Reset();

                target.Initialize();

                UpdateTarget(osmStreamSource, target);

                target.Flush();
                target.Close();
            }
        }

        private static void UpdateTarget(OsmStreamSource osmStreamSource, OsmStreamTarget osmStreamTarget)
        {
            if (useRegisterSource)
            {
                osmStreamTarget.RegisterSource(osmStreamSource, osmGeo => true);
                osmStreamTarget.Pull();
            }
            else
            {
                bool isFirst = true;

                foreach (OsmGeo osmGeo in osmStreamSource)
                {
                    Tag? tag = osmGeo.Tags?.FirstOrDefault(t => t.Key == KeyValuePair.Key);

                    switch (osmGeo.Type)
                    {
                        case OsmGeoType.Node:
                            if (isFirst)
                            {
                                for (int indexer = 0; indexer < 1; indexer++)
                                {
                                    (osmGeo as Node).Tags.Add(new Tag(KeyValuePair.Key + Guid.NewGuid(), KeyValuePair.Value));
                                }

                                isFirst = false;
                            }

                            osmStreamTarget.AddNode(osmGeo as Node);
                            break;
                        case OsmGeoType.Way:
                            osmStreamTarget.AddWay(osmGeo as Way);
                            break;
                        case OsmGeoType.Relation:
                            osmStreamTarget.AddRelation(osmGeo as Relation);
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }
                }
            }
        }
    }
}

Already I posted this question on the GITHube page of OSMSharp as is linked here. Any help would be very appreciated.

来源:https://stackoverflow.com/questions/59599088/open-osm-pbf-results-in-protobuf-exception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!