OSMServer/OsmXmlToRegionConverter/ByteConverter.cs
2023-03-30 16:29:42 +02:00

259 lines
8.6 KiB
C#

using System.Text;
namespace OsmXmlToRegionConverter;
public static class Extensions
{
public static T[] SubArray<T>(this T[] array, int offset, int length)
{
T[] result = new T[length];
Buffer.BlockCopy(array, offset, result, 0, length);
return result;
}
}
public class ByteConverter
{
private enum ContentType : byte
{
Node = 0,
Coordinates = 1,
Edge = 2,
TmpNode = 3,
TmpWay = 4,
Region = 5,
TagManager = 6
}
public static HashSet<object> GetObjectsFromBytes(byte[] bytes)
{
HashSet<object> ret = new HashSet<object>();
while (bytes.Length > 0)
{
ContentType contentType = (ContentType)bytes[0];
switch (contentType)
{
case ContentType.Node:
int edgeCount = BitConverter.ToInt32(bytes, 1);
int byteSizeNode = Node.ByteSizeEmpty + 1 + edgeCount * Edge.ByteSize; //+1 for contenttype of coordinates
ret.Add(Node.FromBytes(bytes.SubArray(1, byteSizeNode)));
bytes = bytes.SubArray(1 + byteSizeNode, bytes.Length - 1 - byteSizeNode); //-1 for overflow
break;
case ContentType.Coordinates:
ret.Add(Coordinates.FromBytes(bytes.SubArray(1, Coordinates.ByteSize)));
bytes = bytes.SubArray(1 + Coordinates.ByteSize, bytes.Length - 1 - Coordinates.ByteSize);
break;
case ContentType.Edge:
ret.Add(Edge.FromBytes(bytes.SubArray(1, Edge.ByteSize)));
bytes = bytes.SubArray(1 + Edge.ByteSize, bytes.Length - 1 - Edge.ByteSize);
break;
case ContentType.TmpNode:
ret.Add(TmpNode.FromBytes(bytes.SubArray(1, TmpNode.ByteSize + 1))); //+1 for contenttype of coordinates
bytes = bytes.SubArray(1 + TmpNode.ByteSize + 1, bytes.Length - 1 - (TmpNode.ByteSize + 1));
break;
case ContentType.TmpWay:
int byteSizeTmpWay = BitConverter.ToInt32(bytes, 1);
ret.Add(TmpWay.FromBytes(bytes.SubArray(1, byteSizeTmpWay)));
bytes = bytes.SubArray(1 + byteSizeTmpWay, bytes.Length - 1 - byteSizeTmpWay);
break;
case ContentType.TagManager:
int totalBytesTagManager = BitConverter.ToInt32(bytes, 1);
ret.Add(TagManager.FromBytes(bytes.SubArray(1 + sizeof(int), totalBytesTagManager)));
bytes = bytes.SubArray(1 + sizeof(int) + totalBytesTagManager, bytes.Length - 1 - sizeof(int) - totalBytesTagManager);
break;
default:
throw new Exception("Unknown Type");
}
}
return ret;
}
public static byte[] GetBytes(Node n)
{
using (MemoryStream m = new MemoryStream())
{
using (BinaryWriter b = new BinaryWriter(m))
{
b.Write((byte)ContentType.Node);
b.Write(n.edges.Count);
b.Write((byte)ContentType.Node);
b.Write(n.id);
b.Write(GetBytes(n.coordinates));
foreach(Edge e in n.edges)
b.Write(GetBytes(e));
}
return m.ToArray();
}
}
public static byte[] GetBytes(Coordinates c)
{
using (MemoryStream m = new MemoryStream())
{
using (BinaryWriter b = new BinaryWriter(m))
{
b.Write((byte)ContentType.Coordinates);
b.Write(c.latitude);
b.Write(c.longitude);
}
return m.ToArray();
}
}
public static byte[] GetBytes(Edge e)
{
using (MemoryStream m = new MemoryStream())
{
using (BinaryWriter b = new BinaryWriter(m))
{
b.Write((byte)ContentType.Edge);
b.Write(e.wayId);
b.Write(e.neighborId);
b.Write(e.neighborRegion);
}
return m.ToArray();
}
}
public static byte[] GetBytes(TmpNode tn)
{
using (MemoryStream m = new MemoryStream())
{
using (BinaryWriter b = new BinaryWriter(m))
{
b.Write((byte)ContentType.TmpNode);
b.Write(tn.id);
b.Write(GetBytes(tn.coordinates));
}
return m.ToArray();
}
}
public static byte[] GetBytes(TmpWay tw)
{
using (MemoryStream m = new MemoryStream())
{
using (BinaryWriter b = new BinaryWriter(m))
{
b.Write((byte)ContentType.TmpWay);
HashSet<byte[]> tagBytesSet = new HashSet<byte[]>();
int totalTagBytes = 0;
foreach (Tag tag in tw.tags)
{
byte[] tagBytes = GetBytes(tag);
totalTagBytes += tagBytes.Length;
tagBytesSet.Add(tagBytes);
}
b.Write(sizeof(ulong) + sizeof(int) + tw.wayNodeIds.Length * sizeof(ulong) + totalTagBytes);
b.Write(tw.id);
b.Write(tw.wayNodeIds.Length);
foreach (ulong wayNodeId in tw.wayNodeIds)
b.Write(wayNodeId);
foreach (byte[] tagBytes in tagBytesSet)
b.Write(tagBytes);
}
return m.ToArray();
}
}
public static byte[] GetBytes(Region r)
{
using (MemoryStream m = new MemoryStream())
{
using (BinaryWriter b = new BinaryWriter(m))
{
b.Write((byte)ContentType.Region);
b.Write(r.GetNodes().Length);
b.Write(r.regionHash);
foreach (Node n in r.GetNodes())
b.Write(GetBytes(n));
}
return m.ToArray();
}
}
public static byte[] GetBytes(Tag tag)
{
using (MemoryStream m = new MemoryStream())
{
using (BinaryWriter b = new BinaryWriter(m))
{
byte[] valueBytes;
if (tag.value is ulong valueUlong)
{
valueBytes = BitConverter.GetBytes(valueUlong);
}else if (tag.value is byte valueByte)
{
valueBytes = new[] { valueByte };
}else if (tag.value is bool valueBool)
{
valueBytes = BitConverter.GetBytes(valueBool);
}else if (tag.value is string valueString)
{
valueBytes = Encoding.ASCII.GetBytes(valueString);
}else if (tag.value is int valueInt)
{
valueBytes = BitConverter.GetBytes(valueInt);
}
else
{
throw new ArgumentException($"Unknown type {tag.value.GetType()}");
}
b.Write(sizeof(byte) + valueBytes.Length);
b.Write((byte)tag.key);
b.Write(valueBytes);
}
return m.ToArray();
}
}
public static byte[] GetBytes(TagManager t)
{
using (MemoryStream m = new MemoryStream())
{
using (BinaryWriter b = new BinaryWriter(m))
{
HashSet<byte[]> wayBytesSet = new HashSet<byte[]>();
int totalBytes = 0;
foreach (KeyValuePair<ulong, HashSet<Tag>> way in t.wayTags)
{
HashSet<byte[]> tagBytesSet = new HashSet<byte[]>();
tagBytesSet.Add(BitConverter.GetBytes(way.Key));
int totalWayBytes = sizeof(ulong);
foreach (Tag tag in way.Value)
{
byte[] tagBytes = GetBytes(tag);
totalWayBytes += tagBytes.Length;
tagBytesSet.Add(tagBytes);
}
wayBytesSet.Add(BitConverter.GetBytes(totalWayBytes));
foreach (byte[] bytes in tagBytesSet)
{
wayBytesSet.Add(bytes);
}
totalBytes += sizeof(int) + totalWayBytes;
}
b.Write(totalBytes);
foreach (byte[] bytes in wayBytesSet)
{
b.Write(bytes);
}
}
return m.ToArray();
}
}
}