using System.Text; namespace OsmXmlToRegionConverter; public static class Extensions { public static T[] SubArray(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 GetObjectsFromBytes(byte[] bytes) { HashSet ret = new HashSet(); 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 tagBytesSet = new HashSet(); 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 wayBytesSet = new HashSet(); int totalBytes = 0; foreach (KeyValuePair> way in t.wayTags) { HashSet tagBytesSet = new HashSet(); 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(); } } }