Updated to C# 12
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>10.0</LangVersion>
|
||||
<TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
|
||||
<LangVersion>12.0</LangVersion>
|
||||
|
||||
<AssemblyName>AMWD.Common</AssemblyName>
|
||||
<RootNamespace>AMWD.Common</RootNamespace>
|
||||
@@ -21,10 +21,23 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MessagePack" Version="2.5.129" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.HttpOverrides" Version="2.2.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Unclassified.DeepConvert" Version="1.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
|
||||
<PackageReference Include="Microsoft.AspNetCore.HttpOverrides" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
|
||||
<_Parameter1>UnitTests</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace AMWD.Common.Cli
|
||||
|
||||
private string[] _args;
|
||||
private List<Argument> _parsedArguments;
|
||||
private readonly List<Option> _options = new();
|
||||
private readonly List<Option> _options = [];
|
||||
|
||||
#endregion Private data
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace AMWD.Common.Cli
|
||||
{
|
||||
args.Add(currentArg.ToString());
|
||||
}
|
||||
return args.ToArray();
|
||||
return [.. args];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -199,7 +199,7 @@ namespace AMWD.Common.Cli
|
||||
}
|
||||
|
||||
// Clear/reset data
|
||||
_parsedArguments = new();
|
||||
_parsedArguments = [];
|
||||
foreach (var option in _options)
|
||||
{
|
||||
option.IsSet = false;
|
||||
@@ -223,7 +223,7 @@ namespace AMWD.Common.Cli
|
||||
string optName = arg.Substring(arg.StartsWith("--") ? 2 : 1);
|
||||
|
||||
// Split option value if separated with : or = instead of whitespace
|
||||
int separatorIndex = optName.IndexOfAny(new[] { ':', '=' });
|
||||
int separatorIndex = optName.IndexOfAny([':', '=']);
|
||||
string optValue = null;
|
||||
if (separatorIndex != -1)
|
||||
{
|
||||
@@ -288,7 +288,7 @@ namespace AMWD.Common.Cli
|
||||
}
|
||||
else
|
||||
{
|
||||
_parsedArguments.Add(new Argument(null, new[] { arg }));
|
||||
_parsedArguments.Add(new Argument(null, [arg]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,7 +315,7 @@ namespace AMWD.Common.Cli
|
||||
if (_parsedArguments == null)
|
||||
Parse();
|
||||
|
||||
return _parsedArguments.ToArray();
|
||||
return [.. _parsedArguments];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,21 +8,16 @@ namespace AMWD.Common.Cli
|
||||
/// Walks through an <see cref="IEnumerable{T}"/> and allows retrieving additional items.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class EnumerableWalker<T> : IEnumerable<T>
|
||||
where T : class
|
||||
/// <remarks>
|
||||
/// Initialises a new instance of the <see cref="EnumerableWalker{T}"/> class.
|
||||
/// </remarks>
|
||||
/// <param name="array">The array to walk though.</param>
|
||||
internal class EnumerableWalker<T>(IEnumerable<T> array)
|
||||
: IEnumerable<T> where T : class
|
||||
{
|
||||
private readonly IEnumerable<T> _array;
|
||||
private readonly IEnumerable<T> _array = array ?? throw new ArgumentNullException(nameof(array));
|
||||
private IEnumerator<T> _enumerator;
|
||||
|
||||
/// <summary>
|
||||
/// Initialises a new instance of the <see cref="EnumerableWalker{T}"/> class.
|
||||
/// </summary>
|
||||
/// <param name="array">The array to walk though.</param>
|
||||
public EnumerableWalker(IEnumerable<T> array)
|
||||
{
|
||||
_array = array ?? throw new ArgumentNullException(nameof(array));
|
||||
}
|
||||
|
||||
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
||||
{
|
||||
_enumerator = _array.GetEnumerator();
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace AMWD.Common.Cli
|
||||
/// <param name="parameterCount">The number of additional parameters for this option.</param>
|
||||
internal Option(string name, int parameterCount)
|
||||
{
|
||||
Names = new List<string>() { name };
|
||||
Names = [name];
|
||||
ParameterCount = parameterCount;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,18 +13,16 @@ namespace Newtonsoft.Json
|
||||
/// <summary>
|
||||
/// List of known types to use this converver.
|
||||
/// </summary>
|
||||
public static readonly Type[] KnownTypes = new[]
|
||||
{
|
||||
public static readonly Type[] KnownTypes =
|
||||
[
|
||||
typeof(byte[]),
|
||||
typeof(List<byte>),
|
||||
typeof(IEnumerable<byte>)
|
||||
};
|
||||
];
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return KnownTypes.Contains(objectType);
|
||||
}
|
||||
=> KnownTypes.Contains(objectType);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
|
||||
@@ -14,19 +14,17 @@ namespace Newtonsoft.Json
|
||||
/// <summary>
|
||||
/// List of known types to use this converver.
|
||||
/// </summary>
|
||||
public static readonly Type[] KnownTypes = new[]
|
||||
{
|
||||
public static readonly Type[] KnownTypes =
|
||||
[
|
||||
typeof(IPAddress),
|
||||
typeof(IPAddress[]),
|
||||
typeof(List<IPAddress>),
|
||||
typeof(IEnumerable<IPAddress>)
|
||||
};
|
||||
];
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return KnownTypes.Contains(objectType);
|
||||
}
|
||||
=> KnownTypes.Contains(objectType);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
#if NET8_0_OR_GREATER
|
||||
using IPNetwork = System.Net.IPNetwork;
|
||||
#else
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
|
||||
#endif
|
||||
|
||||
namespace Newtonsoft.Json
|
||||
{
|
||||
@@ -10,24 +15,22 @@ namespace Newtonsoft.Json
|
||||
/// Converts an <see cref="IPNetwork"/> from and to JSON.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
public class IPNetworkConverter : JsonConverter
|
||||
public class IpNetworkConverter : JsonConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// List of known types to use this converver.
|
||||
/// </summary>
|
||||
public static readonly Type[] KnownTypes = new[]
|
||||
{
|
||||
public static readonly Type[] KnownTypes =
|
||||
[
|
||||
typeof(IPNetwork),
|
||||
typeof(IPNetwork[]),
|
||||
typeof(List<IPNetwork>),
|
||||
typeof(IEnumerable<IPNetwork>)
|
||||
};
|
||||
];
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return KnownTypes.Contains(objectType);
|
||||
}
|
||||
=> KnownTypes.Contains(objectType);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
@@ -40,7 +43,7 @@ namespace Newtonsoft.Json
|
||||
if (typeof(IPNetwork) == objectType)
|
||||
return Parse(str);
|
||||
|
||||
var networks = str.Split(';').Select(s => Parse(s));
|
||||
var networks = str.Split(';').Select(Parse);
|
||||
|
||||
if (typeof(IPNetwork[]) == objectType)
|
||||
return networks.ToArray();
|
||||
@@ -65,23 +68,27 @@ namespace Newtonsoft.Json
|
||||
str = ToString(net);
|
||||
|
||||
if (value is IPNetwork[] netArray)
|
||||
str = string.Join(";", netArray.Select(n => ToString(n)));
|
||||
str = string.Join(";", netArray.Select(ToString));
|
||||
|
||||
if (value is List<IPNetwork> netList)
|
||||
str = string.Join(";", netList.Select(n => ToString(n)));
|
||||
str = string.Join(";", netList.Select(ToString));
|
||||
|
||||
if (value is IEnumerable<IPNetwork> netEnum)
|
||||
str = string.Join(";", netEnum.Select(n => ToString(n)));
|
||||
str = string.Join(";", netEnum.Select(ToString));
|
||||
|
||||
writer.WriteValue(str);
|
||||
}
|
||||
|
||||
private string ToString(IPNetwork net)
|
||||
private static string ToString(IPNetwork net)
|
||||
{
|
||||
#if NET8_0_OR_GREATER
|
||||
return $"{net.BaseAddress}/{net.PrefixLength}";
|
||||
#else
|
||||
return $"{net.Prefix}/{net.PrefixLength}";
|
||||
#endif
|
||||
}
|
||||
|
||||
private IPNetwork Parse(string str)
|
||||
private static IPNetwork Parse(string str)
|
||||
{
|
||||
string[] parts = str.Split('/');
|
||||
var prefix = IPAddress.Parse(parts.First());
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System.Text;
|
||||
|
||||
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("UnitTests")]
|
||||
|
||||
namespace System
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
namespace System
|
||||
@@ -41,13 +40,5 @@ namespace System
|
||||
/// <returns>The description or the string representation of the value.</returns>
|
||||
public static string GetDescription(this Enum value)
|
||||
=> value.GetAttribute<DescriptionAttribute>()?.Description ?? value.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name from <see cref="DisplayAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">The enum value.</param>
|
||||
/// <returns>The display name or the string representation of the value.</returns>
|
||||
public static string GetDisplayName(this Enum value)
|
||||
=> value.GetAttribute<DisplayAttribute>()?.Name ?? value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,16 +56,11 @@
|
||||
return new DisposableReadWriteLock(rwLock, LockMode.Write);
|
||||
}
|
||||
|
||||
private struct DisposableReadWriteLock : IDisposable
|
||||
private struct DisposableReadWriteLock(ReaderWriterLockSlim rwLock, LockMode lockMode)
|
||||
: IDisposable
|
||||
{
|
||||
private readonly ReaderWriterLockSlim _rwLock;
|
||||
private LockMode _lockMode;
|
||||
|
||||
public DisposableReadWriteLock(ReaderWriterLockSlim rwLock, LockMode lockMode)
|
||||
{
|
||||
_rwLock = rwLock;
|
||||
_lockMode = lockMode;
|
||||
}
|
||||
private readonly ReaderWriterLockSlim _rwLock = rwLock;
|
||||
private LockMode _lockMode = lockMode;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace System.IO
|
||||
}
|
||||
while (ch != eol);
|
||||
|
||||
return encoding.GetString(bytes.ToArray()).Trim();
|
||||
return encoding.GetString([.. bytes]).Trim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -73,7 +73,7 @@ namespace System.IO
|
||||
}
|
||||
while (ch != eol);
|
||||
|
||||
return encoding.GetString(bytes.ToArray()).Trim();
|
||||
return encoding.GetString([.. bytes]).Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,12 @@ namespace System
|
||||
/// <summary>
|
||||
/// String extensions.
|
||||
/// </summary>
|
||||
#if NET8_0_OR_GREATER
|
||||
public static partial class StringExtensions
|
||||
#else
|
||||
|
||||
public static class StringExtensions
|
||||
#endif
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a hex string into a byte array.
|
||||
@@ -32,8 +37,13 @@ namespace System
|
||||
if (str.Length % 2 == 1)
|
||||
yield break;
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
if (InvalidHexCharRegex().IsMatch(str))
|
||||
yield break;
|
||||
#else
|
||||
if (Regex.IsMatch(str, "[^0-9a-fA-F]"))
|
||||
yield break;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < str.Length; i += 2)
|
||||
yield return Convert.ToByte(str.Substring(i, 2), 16);
|
||||
@@ -179,14 +189,14 @@ namespace System
|
||||
{
|
||||
var dnsClientType = Type.GetType("DNS.Client.DnsClient, DNS") ?? throw new DllNotFoundException("The DNS NuGet package is required: https://www.nuget.org/packages/DNS/7.0.0");
|
||||
var recordTypeType = Type.GetType("DNS.Protocol.RecordType, DNS");
|
||||
var resolveMethodInfo = dnsClientType.GetMethod("Resolve", new[] { typeof(string), recordTypeType, typeof(CancellationToken) });
|
||||
var resolveMethodInfo = dnsClientType.GetMethod("Resolve", [typeof(string), recordTypeType, typeof(CancellationToken)]);
|
||||
|
||||
bool exists = false;
|
||||
foreach (var nameserver in nameservers)
|
||||
{
|
||||
object dnsClient = Activator.CreateInstance(dnsClientType, new object[] { nameserver });
|
||||
object dnsClient = Activator.CreateInstance(dnsClientType, [nameserver]);
|
||||
|
||||
var waitTask = Task.Run(async () => await resolveMethodInfo.InvokeAsync<object>(dnsClient, new object[] { mailAddress.Host, 15, CancellationToken.None })); // 15 = MX Record
|
||||
var waitTask = Task.Run(async () => await resolveMethodInfo.InvokeAsync<object>(dnsClient, [mailAddress.Host, 15, CancellationToken.None])); // 15 = MX Record
|
||||
waitTask.Wait();
|
||||
|
||||
object response = waitTask.Result;
|
||||
@@ -232,5 +242,10 @@ namespace System
|
||||
/// <returns></returns>
|
||||
public static StringBuilder AppendLine(this StringBuilder sb, string value, string newLine)
|
||||
=> sb.Append(value).Append(newLine);
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
[GeneratedRegex("[^0-9a-fA-F]")]
|
||||
private static partial Regex InvalidHexCharRegex();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using AMWD.Common.Utilities;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
/// <summary>
|
||||
/// Serialization of an <see cref="IPAddress"/> array to and from <see cref="MessagePack"/>.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
public class IPAddressArrayFormatter : IMessagePackFormatter<IPAddress[]>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public IPAddress[] 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 IPAddress[length];
|
||||
while (bytePos < bytes.Length)
|
||||
{
|
||||
byte len = bytes.Skip(bytePos).First();
|
||||
bytePos++;
|
||||
|
||||
buffer = bytes.Skip(bytePos).Take(len).ToArray();
|
||||
bytePos += len;
|
||||
|
||||
array[arrayPos] = new IPAddress(buffer);
|
||||
arrayPos++;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Serialize(ref MessagePackWriter writer, IPAddress[] 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 ip in value)
|
||||
{
|
||||
buffer = ip.GetAddressBytes();
|
||||
bytes.Add((byte)buffer.Length);
|
||||
bytes.AddRange(buffer);
|
||||
}
|
||||
|
||||
options.Resolver.GetFormatterWithVerify<byte[]>().Serialize(ref writer, bytes.ToArray(), options);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
using System.Net;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
/// <summary>
|
||||
/// Serialization of an <see cref="IPAddress"/> to and from <see cref="MessagePack"/>.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
public class IPAddressFormatter : IMessagePackFormatter<IPAddress>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public IPAddress Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.IsNil)
|
||||
return null;
|
||||
|
||||
byte[] bytes = options.Resolver.GetFormatterWithVerify<byte[]>().Deserialize(ref reader, options);
|
||||
return new IPAddress(bytes);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Serialize(ref MessagePackWriter writer, IPAddress value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] bytes = value.GetAddressBytes();
|
||||
options.Resolver.GetFormatterWithVerify<byte[]>().Serialize(ref writer, bytes, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using AMWD.Common.Utilities;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
/// <summary>
|
||||
/// Serialization of an <see cref="IPAddress"/> list to and from <see cref="MessagePack"/>.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||||
public class IPAddressListFormatter : IMessagePackFormatter<List<IPAddress>>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public List<IPAddress> 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<IPAddress>();
|
||||
while (bytePos < bytes.Length)
|
||||
{
|
||||
byte len = bytes.Skip(bytePos).First();
|
||||
bytePos++;
|
||||
|
||||
byte[] buffer = bytes.Skip(bytePos).Take(len).ToArray();
|
||||
bytePos += len;
|
||||
|
||||
list.Add(new IPAddress(buffer));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Serialize(ref MessagePackWriter writer, List<IPAddress> 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 ip in value)
|
||||
{
|
||||
buffer = ip.GetAddressBytes();
|
||||
bytes.Add((byte)buffer.Length);
|
||||
bytes.AddRange(buffer);
|
||||
}
|
||||
|
||||
options.Resolver.GetFormatterWithVerify<byte[]>().Serialize(ref writer, bytes.ToArray(), options);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,6 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("UnitTests")]
|
||||
|
||||
namespace AMWD.Common.Logging
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace AMWD.Common.Packing.Ar
|
||||
/// Writes UNIX ar (archive) files in the GNU format.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Copied from <a href="https://github.com/ygoe/DotnetMakeDeb/blob/v1.1.0/DotnetMakeDeb/Ar/ArWriter.cs"/>
|
||||
/// Copied from: <see href="https://github.com/ygoe/DotnetMakeDeb/blob/v1.1.0/DotnetMakeDeb/Ar/ArWriter.cs">DotnetMakeDeb</see>
|
||||
/// </remarks>
|
||||
public class ArWriter
|
||||
{
|
||||
|
||||
@@ -7,28 +7,24 @@ using AMWD.Common.Packing.Tar.Utils;
|
||||
namespace AMWD.Common.Packing.Tar
|
||||
{
|
||||
/// <summary>
|
||||
/// Extract contents of a tar file represented by a stream for the TarReader constructor
|
||||
/// Extract contents of a tar file represented by a stream for the TarReader constructor.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// https://github.com/ygoe/DotnetMakeDeb/blob/v1.1.0/DotnetMakeDeb/Tar/TarReader.cs
|
||||
/// Constructs TarReader object to read data from `tarredData` stream.
|
||||
/// <br />
|
||||
/// Copied from: <see href="https://github.com/ygoe/DotnetMakeDeb/blob/v1.1.0/DotnetMakeDeb/Tar/TarReader.cs">DotnetMakeDeb</see>
|
||||
/// </remarks>
|
||||
public class TarReader
|
||||
/// <param name="tarredData">A stream to read tar archive from</param>
|
||||
public class TarReader(Stream tarredData)
|
||||
{
|
||||
private readonly byte[] _dataBuffer = new byte[512];
|
||||
private readonly UsTarHeader _header;
|
||||
private readonly Stream _inStream;
|
||||
private readonly UsTarHeader _header = new();
|
||||
private readonly Stream _inStream = tarredData;
|
||||
private long _remainingBytesInFile;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs TarReader object to read data from `tarredData` stream
|
||||
/// Gets the file info (the header).
|
||||
/// </summary>
|
||||
/// <param name="tarredData">A stream to read tar archive from</param>
|
||||
public TarReader(Stream tarredData)
|
||||
{
|
||||
_inStream = tarredData;
|
||||
_header = new UsTarHeader();
|
||||
}
|
||||
|
||||
public ITarHeader FileInfo => _header;
|
||||
|
||||
/// <summary>
|
||||
@@ -66,7 +62,7 @@ namespace AMWD.Common.Packing.Tar
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read data from a current file to a Stream.
|
||||
/// Read data from the current archive to a Stream.
|
||||
/// </summary>
|
||||
/// <param name="dataDestanation">A stream to read data to</param>
|
||||
/// <seealso cref="MoveNext"/>
|
||||
@@ -84,6 +80,11 @@ namespace AMWD.Common.Packing.Tar
|
||||
Debug.WriteLine("tar stream position Read out: " + _inStream.Position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads data from the current archive to a buffer array.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer array.</param>
|
||||
/// <returns>The nuber of bytes read.</returns>
|
||||
protected int Read(out byte[] buffer)
|
||||
{
|
||||
if (_remainingBytesInFile == 0)
|
||||
|
||||
@@ -5,13 +5,32 @@ using AMWD.Common.Packing.Tar.Utils;
|
||||
|
||||
namespace AMWD.Common.Packing.Tar
|
||||
{
|
||||
// https://github.com/ygoe/DotnetMakeDeb/blob/v1.1.0/DotnetMakeDeb/Tar/TarWriter.cs
|
||||
/// <summary>
|
||||
/// Writes a tar (see GNU tar) archive to a stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Copied from: <see href="https://github.com/ygoe/DotnetMakeDeb/blob/v1.1.0/DotnetMakeDeb/Tar/TarWriter.cs">DotnetMakeDeb</see>
|
||||
/// </remarks>
|
||||
public class TarWriter : LegacyTarWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// Initilizes a new instance of the <see cref="TarWriter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="outStream">The stream to write the archive to.</param>
|
||||
public TarWriter(Stream outStream)
|
||||
: base(outStream)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Writes an entry header (file, dir, ...) to the archive.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="lastModificationTime">The last modification time.</param>
|
||||
/// <param name="count">The number of bytes.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="groupId">The group id.</param>
|
||||
/// <param name="mode">The access mode.</param>
|
||||
/// <param name="entryType">The entry type.</param>
|
||||
protected override void WriteHeader(string name, DateTime lastModificationTime, long count, int userId, int groupId, int mode, EntryType entryType)
|
||||
{
|
||||
var tarHeader = new UsTarHeader()
|
||||
@@ -29,6 +48,17 @@ namespace AMWD.Common.Packing.Tar
|
||||
OutStream.Write(tarHeader.GetHeaderValue(), 0, tarHeader.HeaderSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an entry header (file, dir, ...) to the archive.
|
||||
/// Hashes the username and groupname down to a HashCode.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="lastModificationTime">The last modification time.</param>
|
||||
/// <param name="count">The number of bytes.</param>
|
||||
/// <param name="userName">The username.</param>
|
||||
/// <param name="groupName">The group name.</param>
|
||||
/// <param name="mode">The access mode.</param>
|
||||
/// <param name="entryType">The entry type.</param>
|
||||
protected virtual void WriteHeader(string name, DateTime lastModificationTime, long count, string userName, string groupName, int mode, EntryType entryType)
|
||||
{
|
||||
WriteHeader(
|
||||
@@ -41,6 +71,16 @@ namespace AMWD.Common.Packing.Tar
|
||||
entryType: entryType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a file to the archive.
|
||||
/// </summary>
|
||||
/// <param name="name">The file name.</param>
|
||||
/// <param name="dataSizeInBytes">The filesize in bytes.</param>
|
||||
/// <param name="userName">The username.</param>
|
||||
/// <param name="groupName">The group name.</param>
|
||||
/// <param name="mode">The access mode.</param>
|
||||
/// <param name="lastModificationTime">The last modification time.</param>
|
||||
/// <param name="writeDelegate">The write handle.</param>
|
||||
public virtual void Write(string name, long dataSizeInBytes, string userName, string groupName, int mode, DateTime lastModificationTime, WriteDataDelegate writeDelegate)
|
||||
{
|
||||
var writer = new DataWriter(OutStream, dataSizeInBytes);
|
||||
@@ -52,6 +92,16 @@ namespace AMWD.Common.Packing.Tar
|
||||
AlignTo512(dataSizeInBytes, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a file to the archive.
|
||||
/// </summary>
|
||||
/// <param name="data">The file stream to add to the archive.</param>
|
||||
/// <param name="dataSizeInBytes">The filesize in bytes.</param>
|
||||
/// <param name="fileName">The file name.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="groupId">The group id.</param>
|
||||
/// <param name="mode">The access mode.</param>
|
||||
/// <param name="lastModificationTime">The last modification time.</param>
|
||||
public void Write(Stream data, long dataSizeInBytes, string fileName, string userId, string groupId, int mode,
|
||||
DateTime lastModificationTime)
|
||||
{
|
||||
|
||||
@@ -10,11 +10,14 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
/// Implements a legacy TAR writer.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Copied from <a href="https://github.com/ygoe/DotnetMakeDeb/blob/v1.1.0/DotnetMakeDeb/Tar/LegacyTarWriter.cs" />
|
||||
/// Writes tar (see GNU tar) archive to a stream
|
||||
/// <br/>
|
||||
/// Copied from: <see href="https://github.com/ygoe/DotnetMakeDeb/blob/v1.1.0/DotnetMakeDeb/Tar/LegacyTarWriter.cs">DotnetMakeDeb</see>
|
||||
/// </remarks>
|
||||
public class LegacyTarWriter : IDisposable
|
||||
/// <param name="outStream">stream to write archive to</param>
|
||||
public class LegacyTarWriter(Stream outStream) : IDisposable
|
||||
{
|
||||
private readonly Stream _outStream;
|
||||
private readonly Stream _outStream = outStream;
|
||||
private bool _isClosed;
|
||||
|
||||
/// <summary>
|
||||
@@ -22,15 +25,6 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
/// </summary>
|
||||
protected byte[] buffer = new byte[1024];
|
||||
|
||||
/// <summary>
|
||||
/// Writes tar (see GNU tar) archive to a stream
|
||||
/// </summary>
|
||||
/// <param name="outStream">stream to write archive to</param>
|
||||
public LegacyTarWriter(Stream outStream)
|
||||
{
|
||||
_outStream = outStream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to read on zero.
|
||||
/// </summary>
|
||||
@@ -48,20 +42,25 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
=> Close();
|
||||
|
||||
#endregion IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Writes a directory entry.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the directory.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="groupId">The group id.</param>
|
||||
/// <param name="mode">The access mode.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="path"/> is not set.</exception>
|
||||
public void WriteDirectoryEntry(string path, int userId, int groupId, int mode)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
throw new ArgumentNullException("path");
|
||||
throw new ArgumentNullException(nameof(path), "The path is not set.");
|
||||
if (path[path.Length - 1] != '/')
|
||||
{
|
||||
path += '/';
|
||||
}
|
||||
|
||||
DateTime lastWriteTime;
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
@@ -89,40 +88,50 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
WriteHeader(path, lastWriteTime, 0, userId, groupId, mode, EntryType.Directory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a directory and its contents.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory.</param>
|
||||
/// <param name="doRecursive">Write also sub-directories.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="directory"/> is not set.</exception>
|
||||
public void WriteDirectory(string directory, bool doRecursive)
|
||||
{
|
||||
if (string.IsNullOrEmpty(directory))
|
||||
throw new ArgumentNullException("directory");
|
||||
throw new ArgumentNullException(nameof(directory), "The directory is not set.");
|
||||
|
||||
WriteDirectoryEntry(directory, 0, 0, 0755);
|
||||
|
||||
string[] files = Directory.GetFiles(directory);
|
||||
foreach (string fileName in files)
|
||||
{
|
||||
Write(fileName);
|
||||
}
|
||||
|
||||
string[] directories = Directory.GetDirectories(directory);
|
||||
foreach (string dirName in directories)
|
||||
{
|
||||
WriteDirectoryEntry(dirName, 0, 0, 0755);
|
||||
if (doRecursive)
|
||||
{
|
||||
WriteDirectory(dirName, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a file.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The file.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="fileName"/> is not set.</exception>
|
||||
public void Write(string fileName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
throw new ArgumentNullException("fileName");
|
||||
using (FileStream file = File.OpenRead(fileName))
|
||||
{
|
||||
Write(file, file.Length, fileName, 61, 61, 511, File.GetLastWriteTime(file.Name));
|
||||
}
|
||||
throw new ArgumentNullException(nameof(fileName), "The file name is not set.");
|
||||
|
||||
using var fileStream = File.OpenRead(fileName);
|
||||
Write(fileStream, fileStream.Length, fileName, 61, 61, 511, File.GetLastWriteTime(fileStream.Name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a file stream.
|
||||
/// </summary>
|
||||
/// <param name="file">The file stream.</param>
|
||||
public void Write(FileStream file)
|
||||
{
|
||||
string path = Path.GetFullPath(file.Name).Replace(Path.GetPathRoot(file.Name), string.Empty);
|
||||
@@ -130,22 +139,48 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
Write(file, file.Length, path, 61, 61, 511, File.GetLastWriteTime(file.Name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a stream.
|
||||
/// </summary>
|
||||
/// <param name="data">The contents.</param>
|
||||
/// <param name="dataSizeInBytes">The file size in bytes.</param>
|
||||
/// <param name="name">The file name.</param>
|
||||
public void Write(Stream data, long dataSizeInBytes, string name)
|
||||
{
|
||||
Write(data, dataSizeInBytes, name, 61, 61, 511, DateTime.Now);
|
||||
}
|
||||
=> Write(data, dataSizeInBytes, name, 61, 61, 511, DateTime.Now);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a file to the archive.
|
||||
/// </summary>
|
||||
/// <param name="name">The file name.</param>
|
||||
/// <param name="dataSizeInBytes">The file size in bytes.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="groupId">The group id.</param>
|
||||
/// <param name="mode">The access mode.</param>
|
||||
/// <param name="lastModificationTime">The last modification timestamp.</param>
|
||||
/// <param name="writeDelegate">The <see cref="WriteDataDelegate"/>.</param>
|
||||
public virtual void Write(string name, long dataSizeInBytes, int userId, int groupId, int mode, DateTime lastModificationTime, WriteDataDelegate writeDelegate)
|
||||
{
|
||||
IArchiveDataWriter writer = new DataWriter(OutStream, dataSizeInBytes);
|
||||
var writer = new DataWriter(OutStream, dataSizeInBytes);
|
||||
|
||||
WriteHeader(name, lastModificationTime, dataSizeInBytes, userId, groupId, mode, EntryType.File);
|
||||
|
||||
while (writer.CanWrite)
|
||||
{
|
||||
writeDelegate(writer);
|
||||
}
|
||||
|
||||
AlignTo512(dataSizeInBytes, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a stream as file to the archive.
|
||||
/// </summary>
|
||||
/// <param name="data">The content as <see cref="Stream"/>.</param>
|
||||
/// <param name="dataSizeInBytes">The file size in bytes.</param>
|
||||
/// <param name="name">The file name.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="groupId">The group id.</param>
|
||||
/// <param name="mode">The access mode.</param>
|
||||
/// <param name="lastModificationTime">The last modification timestamp.</param>
|
||||
/// <exception cref="TarException">This writer is already closed.</exception>
|
||||
public virtual void Write(Stream data, long dataSizeInBytes, string name, int userId, int groupId, int mode, DateTime lastModificationTime)
|
||||
{
|
||||
if (_isClosed)
|
||||
@@ -189,21 +224,26 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
Encoding.UTF8.GetBytes(name, 0, name.Length, entryName, 0);
|
||||
|
||||
// add a "././@LongLink" pseudo-entry which contains the full name
|
||||
using (var nameStream = new MemoryStream(entryName))
|
||||
{
|
||||
WriteHeader("././@LongLink", lastModificationTime, entryName.Length, userId, groupId, mode, EntryType.LongName);
|
||||
WriteContent(entryName.Length, nameStream);
|
||||
AlignTo512(entryName.Length, false);
|
||||
}
|
||||
using var nameStream = new MemoryStream(entryName);
|
||||
WriteHeader("././@LongLink", lastModificationTime, entryName.Length, userId, groupId, mode, EntryType.LongName);
|
||||
WriteContent(entryName.Length, nameStream);
|
||||
AlignTo512(entryName.Length, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a stream as file to the archive.
|
||||
/// </summary>
|
||||
/// <param name="count">The size of the file in bytes.</param>
|
||||
/// <param name="data">The file content as stream.</param>
|
||||
/// <exception cref="IOException"><paramref name="data"/> has not enough to read from.</exception>
|
||||
protected void WriteContent(long count, Stream data)
|
||||
{
|
||||
while (count > 0 && count > buffer.Length)
|
||||
{
|
||||
int bytesRead = data.Read(buffer, 0, buffer.Length);
|
||||
if (bytesRead < 0)
|
||||
throw new IOException("LegacyTarWriter unable to read from provided stream");
|
||||
throw new IOException($"{nameof(LegacyTarWriter)} unable to read from provided stream");
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
if (ReadOnZero)
|
||||
@@ -218,7 +258,8 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
{
|
||||
int bytesRead = data.Read(buffer, 0, (int)count);
|
||||
if (bytesRead < 0)
|
||||
throw new IOException("LegacyTarWriter unable to read from provided stream");
|
||||
throw new IOException($"{nameof(LegacyTarWriter)} unable to read from provided stream");
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
while (count > 0)
|
||||
@@ -232,6 +273,16 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a entry header to the archive.
|
||||
/// </summary>
|
||||
/// <param name="name">The file name.</param>
|
||||
/// <param name="lastModificationTime">The last modification time.</param>
|
||||
/// <param name="count">The number of bytes.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="groupId">The group id.</param>
|
||||
/// <param name="mode">The file mode.</param>
|
||||
/// <param name="entryType">The entry type</param>
|
||||
protected virtual void WriteHeader(string name, DateTime lastModificationTime, long count, int userId, int groupId, int mode, EntryType entryType)
|
||||
{
|
||||
var header = new TarHeader
|
||||
@@ -247,6 +298,9 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
OutStream.Write(header.GetHeaderValue(), 0, header.HeaderSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aligns the entry to 512 bytes.
|
||||
/// </summary>
|
||||
public void AlignTo512(long size, bool acceptZero)
|
||||
{
|
||||
size %= 512;
|
||||
@@ -258,6 +312,9 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the writer and aligns to 512 bytes.
|
||||
/// </summary>
|
||||
public virtual void Close()
|
||||
{
|
||||
if (_isClosed)
|
||||
|
||||
@@ -2,10 +2,51 @@
|
||||
|
||||
namespace AMWD.Common.Packing.Tar.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents errors that occur during tar archive execution.
|
||||
/// </summary>
|
||||
public class TarException : Exception
|
||||
{
|
||||
public TarException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TarException"/> class.
|
||||
/// </summary>
|
||||
public TarException()
|
||||
: base()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TarException"/> class with a specified
|
||||
/// error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public TarException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the System.Exception class with a specified error
|
||||
/// message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference
|
||||
/// if no inner exception is specified.</param>
|
||||
public TarException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
#if !NET8_0_OR_GREATER
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TarException"/> class with serialized data.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="System.Runtime.Serialization.SerializationInfo"/> that holds the serialized
|
||||
/// object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="System.Runtime.Serialization.StreamingContext"/> that contains contextual information
|
||||
/// about the source or destination.</param>
|
||||
protected TarException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace System.Collections.Generic
|
||||
/// Determines whether an element is in the <see cref="AsyncQueue{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="item">The object to locate in the <see cref="AsyncQueue{T}"/>. The value can be null for reference types.</param>
|
||||
/// <returns>true if item is found in the <see cref="AsyncQueue{T}"/>; otherwise, false.</returns>
|
||||
/// <returns><see langword="true"/> if item is found in the <see cref="AsyncQueue{T}"/>, otherwise <see langword="false"/>.</returns>
|
||||
[ExcludeFromCodeCoverage]
|
||||
public bool Contains(T item)
|
||||
{
|
||||
@@ -172,7 +172,7 @@ namespace System.Collections.Generic
|
||||
{
|
||||
lock (_queue)
|
||||
{
|
||||
return _queue.ToArray();
|
||||
return [.. _queue];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ namespace System.Collections.Generic
|
||||
/// Removes the object at the beginning of the <see cref="AsyncQueue{T}"/>, and copies it to the <paramref name="result"/> parameter.
|
||||
/// </summary>
|
||||
/// <param name="result">The removed object.</param>
|
||||
/// <returns>true if the object is successfully removed; false if the <see cref="AsyncQueue{T}"/> is empty.</returns>
|
||||
/// <returns><see langword="true"/> if the object is successfully removed, <see langword="false"/> if the <see cref="AsyncQueue{T}"/> is empty.</returns>
|
||||
public bool TryDequeue(out T result)
|
||||
{
|
||||
try
|
||||
@@ -325,7 +325,7 @@ namespace System.Collections.Generic
|
||||
/// <paramref name="result"/> parameter. The object is not removed from the <see cref="AsyncQueue{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="result">If present, the object at the beginning of the <see cref="AsyncQueue{T}"/>; otherwise, the default value of <typeparamref name="T"/>.</param>
|
||||
/// <returns>true if there is an object at the beginning of the <see cref="AsyncQueue{T}"/>; false if the <see cref="AsyncQueue{T}"/> is empty.</returns>
|
||||
/// <returns><see langword="true"/> if there is an object at the beginning of the <see cref="AsyncQueue{T}"/>, <see langword="false"/> if the <see cref="AsyncQueue{T}"/> is empty.</returns>
|
||||
public bool TryPeek(out T result)
|
||||
{
|
||||
try
|
||||
@@ -344,7 +344,7 @@ namespace System.Collections.Generic
|
||||
/// Removes the first occurrence of a specific object from the <see cref="AsyncQueue{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="item">The object to remove from the <see cref="AsyncQueue{T}"/>. The value can be null for reference types.</param>
|
||||
/// <returns>true if item is successfully removed; otherwise, false. This method also returns false if item was not found in the <see cref="AsyncQueue{T}"/>.</returns>
|
||||
/// <returns><see langword="true"/> if item is successfully removed, otherwise <see langword="false"/>. This method also returns <see langword="false"/> if item was not found in the <see cref="AsyncQueue{T}"/>.</returns>
|
||||
public bool Remove(T item)
|
||||
{
|
||||
lock (_queue)
|
||||
|
||||
@@ -171,6 +171,7 @@ namespace System.Security.Cryptography
|
||||
#region Static methods
|
||||
|
||||
#region Encryption
|
||||
#pragma warning disable SYSLIB0041
|
||||
|
||||
#region AES
|
||||
|
||||
@@ -185,7 +186,11 @@ namespace System.Security.Cryptography
|
||||
byte[] salt = new byte[_saltLength];
|
||||
Array.Copy(cipher, salt, _saltLength);
|
||||
|
||||
using var gen = new Rfc2898DeriveBytes(password, salt);
|
||||
#if NET8_0_OR_GREATER
|
||||
using var gen = new Rfc2898DeriveBytes(password, salt, 1000, HashAlgorithmName.SHA1);
|
||||
#else
|
||||
using var gen = new Rfc2898DeriveBytes(password, salt, 1000);
|
||||
#endif
|
||||
using var aes = Aes.Create();
|
||||
|
||||
aes.Mode = CipherMode.CBC;
|
||||
@@ -225,7 +230,11 @@ namespace System.Security.Cryptography
|
||||
{
|
||||
byte[] salt = GetRandomBytes(_saltLength);
|
||||
|
||||
using var gen = new Rfc2898DeriveBytes(password, salt);
|
||||
#if NET8_0_OR_GREATER
|
||||
using var gen = new Rfc2898DeriveBytes(password, salt, 1000, HashAlgorithmName.SHA1);
|
||||
#else
|
||||
using var gen = new Rfc2898DeriveBytes(password, salt, 1000);
|
||||
#endif
|
||||
using var aes = Aes.Create();
|
||||
|
||||
aes.Mode = CipherMode.CBC;
|
||||
@@ -271,7 +280,11 @@ namespace System.Security.Cryptography
|
||||
byte[] salt = new byte[_saltLength];
|
||||
Array.Copy(cipher, salt, _saltLength);
|
||||
|
||||
using var gen = new Rfc2898DeriveBytes(password, salt);
|
||||
#if NET8_0_OR_GREATER
|
||||
using var gen = new Rfc2898DeriveBytes(password, salt, 1000, HashAlgorithmName.SHA1);
|
||||
#else
|
||||
using var gen = new Rfc2898DeriveBytes(password, salt, 1000);
|
||||
#endif
|
||||
using var tdes = TripleDES.Create();
|
||||
|
||||
tdes.Mode = CipherMode.CBC;
|
||||
@@ -298,7 +311,11 @@ namespace System.Security.Cryptography
|
||||
{
|
||||
byte[] salt = GetRandomBytes(_saltLength);
|
||||
|
||||
using var gen = new Rfc2898DeriveBytes(password, salt);
|
||||
#if NET8_0_OR_GREATER
|
||||
using var gen = new Rfc2898DeriveBytes(password, salt, 1000, HashAlgorithmName.SHA1);
|
||||
#else
|
||||
using var gen = new Rfc2898DeriveBytes(password, salt, 1000);
|
||||
#endif
|
||||
using var tdes = TripleDES.Create();
|
||||
|
||||
tdes.Mode = CipherMode.CBC;
|
||||
@@ -344,6 +361,7 @@ namespace System.Security.Cryptography
|
||||
|
||||
#endregion Triple DES
|
||||
|
||||
#pragma warning restore SYSLIB0041
|
||||
#endregion Encryption
|
||||
|
||||
#region Hashing
|
||||
@@ -379,8 +397,12 @@ namespace System.Security.Cryptography
|
||||
/// <returns>The MD5 hash value, in hexadecimal notation.</returns>
|
||||
public static string Md5(byte[] bytes)
|
||||
{
|
||||
#if NET8_0_OR_GREATER
|
||||
return MD5.HashData(bytes).BytesToHex();
|
||||
#else
|
||||
using var md5 = MD5.Create();
|
||||
return md5.ComputeHash(bytes).BytesToHex();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion MD5
|
||||
@@ -416,8 +438,12 @@ namespace System.Security.Cryptography
|
||||
/// <returns>The SHA-1 hash value, in hexadecimal notation.</returns>
|
||||
public static string Sha1(byte[] bytes)
|
||||
{
|
||||
#if NET8_0_OR_GREATER
|
||||
return SHA1.HashData(bytes).BytesToHex();
|
||||
#else
|
||||
using var sha1 = SHA1.Create();
|
||||
return sha1.ComputeHash(bytes).BytesToHex();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion SHA-1
|
||||
@@ -453,8 +479,12 @@ namespace System.Security.Cryptography
|
||||
/// <returns>The SHA-256 hash value, in hexadecimal notation.</returns>
|
||||
public static string Sha256(byte[] bytes)
|
||||
{
|
||||
#if NET8_0_OR_GREATER
|
||||
return SHA256.HashData(bytes).BytesToHex();
|
||||
#else
|
||||
using var sha256 = SHA256.Create();
|
||||
return sha256.ComputeHash(bytes).BytesToHex();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion SHA-256
|
||||
@@ -490,8 +520,12 @@ namespace System.Security.Cryptography
|
||||
/// <returns>The SHA-512 hash value, in hexadecimal notation.</returns>
|
||||
public static string Sha512(byte[] bytes)
|
||||
{
|
||||
#if NET8_0_OR_GREATER
|
||||
return SHA512.HashData(bytes).BytesToHex();
|
||||
#else
|
||||
using var sha512 = SHA512.Create();
|
||||
return sha512.ComputeHash(bytes).BytesToHex();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion SHA-512
|
||||
|
||||
@@ -4,7 +4,12 @@ using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
#if NET8_0_OR_GREATER
|
||||
using IPNetwork = System.Net.IPNetwork;
|
||||
#else
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
|
||||
#endif
|
||||
|
||||
namespace AMWD.Common.Utilities
|
||||
{
|
||||
@@ -23,7 +28,7 @@ namespace AMWD.Common.Utilities
|
||||
public static List<IPAddress> ResolveHost(string hostname, AddressFamily addressFamily = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(hostname))
|
||||
return new();
|
||||
return [];
|
||||
|
||||
if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6)
|
||||
addressFamily = AddressFamily.Unspecified;
|
||||
@@ -31,7 +36,7 @@ namespace AMWD.Common.Utilities
|
||||
var ipAddress = ResolveIpAddress(hostname, addressFamily);
|
||||
// the name was an ip address, should not happen but experience tells other stories
|
||||
if (ipAddress != null)
|
||||
return new() { ipAddress };
|
||||
return [ipAddress];
|
||||
|
||||
try
|
||||
{
|
||||
@@ -41,7 +46,7 @@ namespace AMWD.Common.Utilities
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new();
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +59,7 @@ namespace AMWD.Common.Utilities
|
||||
public static List<IPAddress> ResolveInterface(string interfaceName, AddressFamily addressFamily = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(interfaceName))
|
||||
return new();
|
||||
return [];
|
||||
|
||||
if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6)
|
||||
addressFamily = AddressFamily.Unspecified;
|
||||
@@ -62,7 +67,7 @@ namespace AMWD.Common.Utilities
|
||||
var ipAddress = ResolveIpAddress(interfaceName, addressFamily);
|
||||
// the name was an ip address, should not happen but experience tells other stories
|
||||
if (ipAddress != null)
|
||||
return new() { ipAddress };
|
||||
return [ipAddress];
|
||||
|
||||
try
|
||||
{
|
||||
@@ -74,45 +79,7 @@ namespace AMWD.Common.Utilities
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a CIDR network definition.
|
||||
/// </summary>
|
||||
/// <param name="network">The network in CIDR.</param>
|
||||
/// <returns>The <see cref="IPNetwork"/> or <c>null</c>.</returns>
|
||||
public static IPNetwork ParseNetwork(string network)
|
||||
{
|
||||
TryParseNetwork(network, out var ipNetwork);
|
||||
return ipNetwork;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to parse a CIDR network definition.
|
||||
/// </summary>
|
||||
/// <param name="network">The network in CIDR.</param>
|
||||
/// <param name="ipNetwork">The parsed <see cref="IPNetwork"/>.</param>
|
||||
/// <returns><c>true</c> on success, otherwise <c>false</c>.</returns>
|
||||
public static bool TryParseNetwork(string network, out IPNetwork ipNetwork)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] parts = network.Split('/');
|
||||
if (parts.Length != 2)
|
||||
throw new ArgumentException($"Invalid network type");
|
||||
|
||||
var prefix = IPAddress.Parse(parts.First());
|
||||
int prefixLength = int.Parse(parts.Last());
|
||||
|
||||
ipNetwork = new IPNetwork(prefix, prefixLength);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
ipNetwork = null;
|
||||
return false;
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +95,11 @@ namespace AMWD.Common.Utilities
|
||||
{
|
||||
var list = new List<IPAddress>();
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
var ipAddress = network.BaseAddress;
|
||||
#else
|
||||
var ipAddress = network.Prefix;
|
||||
#endif
|
||||
while (network.Contains(ipAddress))
|
||||
{
|
||||
list.Add(ipAddress);
|
||||
|
||||
Reference in New Issue
Block a user