1
0

Adding IPNetwork to Converter/Formatters

This commit is contained in:
2022-08-05 17:21:31 +02:00
parent 1522c0cbc9
commit 7ee10e4a6d
9 changed files with 310 additions and 17 deletions

View File

@@ -69,7 +69,7 @@ namespace Newtonsoft.Json
if (value is List<IPAddress> addrList)
str = string.Join(";", addrList.Select(ip => ip.ToString()));
if (value is List<IPAddress> addrEnum)
if (value is IEnumerable<IPAddress> addrEnum)
str = string.Join(";", addrEnum.Select(ip => ip.ToString()));
writer.WriteValue(str);

View File

@@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Microsoft.AspNetCore.HttpOverrides;
namespace Newtonsoft.Json
{
/// <summary>
/// Converts an <see cref="IPNetwork"/> from and to JSON.
/// </summary>
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class IPNetworkConverter : JsonConverter
{
/// <summary>
/// List of known types to use this converver.
/// </summary>
public static readonly Type[] KnownTypes = new[]
{
typeof(IPNetwork),
typeof(IPNetwork[]),
typeof(List<IPNetwork>),
typeof(IEnumerable<IPNetwork>)
};
/// <inheritdoc/>
public override bool CanConvert(Type objectType)
{
return KnownTypes.Contains(objectType);
}
/// <inheritdoc/>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.Value == null)
return null;
string str = (string)reader.Value;
if (typeof(IPNetwork) == objectType)
return Parse(str);
var networks = str.Split(';').Select(s => Parse(s));
if (typeof(IPNetwork[]) == objectType)
return networks.ToArray();
if (typeof(List<IPNetwork>) == objectType)
return networks.ToList();
return networks;
}
/// <inheritdoc/>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
string str = null;
if (value == null)
{
writer.WriteValue(str);
return;
}
if (value is IPNetwork net)
str = ToString(net);
if (value is IPNetwork[] netArray)
str = string.Join(";", netArray.Select(n => ToString(n)));
if (value is List<IPNetwork> netList)
str = string.Join(";", netList.Select(n => ToString(n)));
if (value is IEnumerable<IPNetwork> netEnum)
str = string.Join(";", netEnum.Select(n => ToString(n)));
writer.WriteValue(str);
}
private string ToString(IPNetwork net)
{
return $"{net.Prefix}/{net.PrefixLength}";
}
private IPNetwork Parse(string str)
{
string[] parts = str.Split('/');
var prefix = IPAddress.Parse(parts.First());
int prefixLength = int.Parse(parts.Last());
return new IPNetwork(prefix, prefixLength);
}
}
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using AMWD.Common.Utilities;
namespace MessagePack.Formatters
{
@@ -22,7 +23,7 @@ namespace MessagePack.Formatters
byte[] buffer = bytes.Skip(bytePos).Take(sizeof(int)).ToArray();
bytePos += sizeof(int);
Swap(buffer);
NetworkHelper.SwapBigEndian(buffer);
int length = BitConverter.ToInt32(buffer, 0);
int arrayPos = 0;
@@ -55,7 +56,7 @@ namespace MessagePack.Formatters
int length = value.Length;
byte[] buffer = BitConverter.GetBytes(length);
Swap(buffer);
NetworkHelper.SwapBigEndian(buffer);
bytes.AddRange(buffer);
foreach (var ip in value)
@@ -67,11 +68,5 @@ namespace MessagePack.Formatters
options.Resolver.GetFormatterWithVerify<byte[]>().Serialize(ref writer, bytes.ToArray(), options);
}
private void Swap(byte[] bytes)
{
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
}
}
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using AMWD.Common.Utilities;
namespace MessagePack.Formatters
{
@@ -50,7 +51,7 @@ namespace MessagePack.Formatters
int length = value.Count;
byte[] buffer = BitConverter.GetBytes(length);
Swap(buffer);
NetworkHelper.SwapBigEndian(buffer);
bytes.AddRange(buffer);
foreach (var ip in value)
@@ -62,11 +63,5 @@ namespace MessagePack.Formatters
options.Resolver.GetFormatterWithVerify<byte[]>().Serialize(ref writer, bytes.ToArray(), options);
}
private void Swap(byte[] bytes)
{
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
}
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AMWD.Common.Utilities;
using MessagePack;
using MessagePack.Formatters;
using Microsoft.AspNetCore.HttpOverrides;
namespace AMWD.Common.Formatters
{
/// <summary>
/// Serialization of an <see cref="IPNetwork"/> array to and from <see cref="MessagePack"/>.
/// </summary>
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class IPNetworkArrayFormatter : IMessagePackFormatter<IPNetwork[]>
{
/// <inheritdoc/>
public IPNetwork[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
if (reader.IsNil)
return null;
int bytePos = 0;
byte[] bytes = options.Resolver.GetFormatterWithVerify<byte[]>().Deserialize(ref reader, options);
byte[] buffer = bytes.Skip(bytePos).Take(sizeof(int)).ToArray();
bytePos += sizeof(int);
NetworkHelper.SwapBigEndian(buffer);
int length = BitConverter.ToInt32(buffer, 0);
int arrayPos = 0;
var array = new IPNetwork[length];
while (bytePos < bytes.Length)
{
byte len = bytes.Skip(bytePos).First();
bytePos++;
buffer = bytes.Skip(bytePos).Take(len).ToArray();
bytePos += len;
array[arrayPos] = IPNetworkFormatter.DeserializeInternal(buffer);
arrayPos++;
}
return array;
}
/// <inheritdoc/>
public void Serialize(ref MessagePackWriter writer, IPNetwork[] value, MessagePackSerializerOptions options)
{
if (value == null)
{
writer.WriteNil();
return;
}
var bytes = new List<byte>();
int length = value.Length;
byte[] buffer = BitConverter.GetBytes(length);
NetworkHelper.SwapBigEndian(buffer);
bytes.AddRange(buffer);
foreach (var network in value)
{
buffer = IPNetworkFormatter.SerializeInternal(network);
bytes.Add((byte)buffer.Length);
bytes.AddRange(buffer);
}
options.Resolver.GetFormatterWithVerify<byte[]>().Serialize(ref writer, bytes.ToArray(), options);
}
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Linq;
using System.Net;
using Microsoft.AspNetCore.HttpOverrides;
namespace MessagePack.Formatters
{
/// <summary>
/// Serialization of an <see cref="IPNetwork"/> to and from <see cref="MessagePack"/>.
/// </summary>
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class IPNetworkFormatter : IMessagePackFormatter<IPNetwork>
{
/// <inheritdoc/>
public IPNetwork Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
if (reader.IsNil)
return null;
byte[] bytes = options.Resolver.GetFormatterWithVerify<byte[]>().Deserialize(ref reader, options);
return DeserializeInternal(bytes);
}
/// <inheritdoc/>
public void Serialize(ref MessagePackWriter writer, IPNetwork value, MessagePackSerializerOptions options)
{
if (value == null)
{
writer.WriteNil();
return;
}
byte[] bytes = SerializeInternal(value);
options.Resolver.GetFormatterWithVerify<byte[]>().Serialize(ref writer, bytes, options);
}
internal static byte[] SerializeInternal(IPNetwork network)
{
// IP network prefix has a maximum of 128 bit - therefore the length can be covered with a byte.
byte prefixLength = (byte)network.PrefixLength;
byte[] prefixBytes = network.Prefix.GetAddressBytes();
byte[] bytes = new byte[prefixBytes.Length + 1];
bytes[0] = prefixLength;
Array.Copy(prefixBytes, 0, bytes, 1, prefixBytes.Length);
return bytes;
}
internal static IPNetwork DeserializeInternal(byte[] bytes)
{
byte prefixLength = bytes[0];
byte[] prefixBytes = bytes.Skip(1).ToArray();
var prefix = new IPAddress(prefixBytes);
return new IPNetwork(prefix, prefixLength);
}
}
}

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AMWD.Common.Utilities;
using Microsoft.AspNetCore.HttpOverrides;
namespace MessagePack.Formatters
{
/// <summary>
/// Serialization of an <see cref="IPNetwork"/> list to and from <see cref="MessagePack"/>.
/// </summary>
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class IPNetworkListFormatter : IMessagePackFormatter<List<IPNetwork>>
{
/// <inheritdoc/>
public List<IPNetwork> Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
if (reader.IsNil)
return null;
byte[] bytes = options.Resolver.GetFormatterWithVerify<byte[]>().Deserialize(ref reader, options);
// skipping the length information
int bytePos = sizeof(int);
var list = new List<IPNetwork>();
while (bytePos < bytes.Length)
{
byte len = bytes.Skip(bytePos).First();
bytePos++;
byte[] buffer = bytes.Skip(bytePos).Take(len).ToArray();
bytePos += len;
list.Add(IPNetworkFormatter.DeserializeInternal(buffer));
}
return list;
}
/// <inheritdoc/>
public void Serialize(ref MessagePackWriter writer, List<IPNetwork> value, MessagePackSerializerOptions options)
{
if (value == null)
{
writer.WriteNil();
return;
}
var bytes = new List<byte>();
int length = value.Count;
byte[] buffer = BitConverter.GetBytes(length);
NetworkHelper.SwapBigEndian(buffer);
bytes.AddRange(buffer);
foreach (var network in value)
{
buffer = IPNetworkFormatter.SerializeInternal(network);
bytes.Add((byte)buffer.Length);
bytes.AddRange(buffer);
}
options.Resolver.GetFormatterWithVerify<byte[]>().Serialize(ref writer, bytes.ToArray(), options);
}
}
}

View File

@@ -163,5 +163,11 @@ namespace AMWD.Common.Utilities
.Where(a => addressFamily == AddressFamily.Unspecified || a.AddressFamily == addressFamily)
.OrderBy(a => a.AddressFamily);
}
internal static void SwapBigEndian(byte[] array)
{
if (BitConverter.IsLittleEndian)
Array.Reverse(array);
}
}
}