mirror of
https://github.com/aaru-dps/Aaru.Helpers.git
synced 2025-12-16 19:24:35 +00:00
Move to file scoped namespaces.
This commit is contained in:
77
ArrayFill.cs
77
ArrayFill.cs
@@ -27,55 +27,54 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Aaru.Helpers
|
||||
namespace Aaru.Helpers;
|
||||
|
||||
public static partial class ArrayHelpers
|
||||
{
|
||||
public static partial class ArrayHelpers
|
||||
/// <summary>Fills an array with the specified value</summary>
|
||||
/// <param name="destinationArray">Array</param>
|
||||
/// <param name="value">Value</param>
|
||||
/// <typeparam name="T">Array type</typeparam>
|
||||
public static void ArrayFill<T>(T[] destinationArray, T value) => ArrayFill(destinationArray, new[]
|
||||
{
|
||||
/// <summary>Fills an array with the specified value</summary>
|
||||
/// <param name="destinationArray">Array</param>
|
||||
/// <param name="value">Value</param>
|
||||
/// <typeparam name="T">Array type</typeparam>
|
||||
public static void ArrayFill<T>(T[] destinationArray, T value) => ArrayFill(destinationArray, new[]
|
||||
{
|
||||
value
|
||||
});
|
||||
value
|
||||
});
|
||||
|
||||
/// <summary>Fills an array with the contents of the specified array</summary>
|
||||
/// <param name="destinationArray">Array</param>
|
||||
/// <param name="value">Value</param>
|
||||
/// <typeparam name="T">Array type</typeparam>
|
||||
public static void ArrayFill<T>(T[] destinationArray, T[] value)
|
||||
{
|
||||
if(destinationArray == null)
|
||||
throw new ArgumentNullException(nameof(destinationArray));
|
||||
/// <summary>Fills an array with the contents of the specified array</summary>
|
||||
/// <param name="destinationArray">Array</param>
|
||||
/// <param name="value">Value</param>
|
||||
/// <typeparam name="T">Array type</typeparam>
|
||||
public static void ArrayFill<T>(T[] destinationArray, T[] value)
|
||||
{
|
||||
if(destinationArray == null)
|
||||
throw new ArgumentNullException(nameof(destinationArray));
|
||||
|
||||
if(value.Length > destinationArray.Length)
|
||||
throw new ArgumentException("Length of value array must not be more than length of destination");
|
||||
if(value.Length > destinationArray.Length)
|
||||
throw new ArgumentException("Length of value array must not be more than length of destination");
|
||||
|
||||
// set the initial array value
|
||||
Array.Copy(value, destinationArray, value.Length);
|
||||
// set the initial array value
|
||||
Array.Copy(value, destinationArray, value.Length);
|
||||
|
||||
int arrayToFillHalfLength = destinationArray.Length / 2;
|
||||
int copyLength;
|
||||
int arrayToFillHalfLength = destinationArray.Length / 2;
|
||||
int copyLength;
|
||||
|
||||
for(copyLength = value.Length; copyLength < arrayToFillHalfLength; copyLength <<= 1)
|
||||
Array.Copy(destinationArray, 0, destinationArray, copyLength, copyLength);
|
||||
for(copyLength = value.Length; copyLength < arrayToFillHalfLength; copyLength <<= 1)
|
||||
Array.Copy(destinationArray, 0, destinationArray, copyLength, copyLength);
|
||||
|
||||
Array.Copy(destinationArray, 0, destinationArray, copyLength, destinationArray.Length - copyLength);
|
||||
}
|
||||
Array.Copy(destinationArray, 0, destinationArray, copyLength, destinationArray.Length - copyLength);
|
||||
}
|
||||
|
||||
/// <summary>Converts a byte array to its hexadecimal representation</summary>
|
||||
/// <param name="array">Byte array</param>
|
||||
/// <param name="upper"><c>true</c> to use uppercase</param>
|
||||
/// <returns></returns>
|
||||
public static string ByteArrayToHex(byte[] array, bool upper = false)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
/// <summary>Converts a byte array to its hexadecimal representation</summary>
|
||||
/// <param name="array">Byte array</param>
|
||||
/// <param name="upper"><c>true</c> to use uppercase</param>
|
||||
/// <returns></returns>
|
||||
public static string ByteArrayToHex(byte[] array, bool upper = false)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
for(long i = 0; i < array.LongLength; i++)
|
||||
sb.AppendFormat("{0:x2}", array[i]);
|
||||
for(long i = 0; i < array.LongLength; i++)
|
||||
sb.AppendFormat("{0:x2}", array[i]);
|
||||
|
||||
return upper ? sb.ToString().ToUpper() : sb.ToString();
|
||||
}
|
||||
return upper ? sb.ToString().ToUpper() : sb.ToString();
|
||||
}
|
||||
}
|
||||
@@ -32,19 +32,18 @@
|
||||
|
||||
using System.Linq;
|
||||
|
||||
namespace Aaru.Helpers
|
||||
{
|
||||
/// <summary>Helper operations to work with arrays</summary>
|
||||
public static partial class ArrayHelpers
|
||||
{
|
||||
/// <summary>Checks if an array is null, filled with the NULL byte (0x00) or ASCII whitespace (0x20)</summary>
|
||||
/// <param name="array">Array</param>
|
||||
/// <returns>True if null or whitespace</returns>
|
||||
public static bool ArrayIsNullOrWhiteSpace(byte[] array) => array?.All(b => b == 0x00 || b == 0x20) != false;
|
||||
namespace Aaru.Helpers;
|
||||
|
||||
/// <summary>Checks if an array is null or filled with the NULL byte (0x00)</summary>
|
||||
/// <param name="array">Array</param>
|
||||
/// <returns>True if null</returns>
|
||||
public static bool ArrayIsNullOrEmpty(byte[] array) => array?.All(b => b == 0x00) != false;
|
||||
}
|
||||
/// <summary>Helper operations to work with arrays</summary>
|
||||
public static partial class ArrayHelpers
|
||||
{
|
||||
/// <summary>Checks if an array is null, filled with the NULL byte (0x00) or ASCII whitespace (0x20)</summary>
|
||||
/// <param name="array">Array</param>
|
||||
/// <returns>True if null or whitespace</returns>
|
||||
public static bool ArrayIsNullOrWhiteSpace(byte[] array) => array?.All(b => b == 0x00 || b == 0x20) != false;
|
||||
|
||||
/// <summary>Checks if an array is null or filled with the NULL byte (0x00)</summary>
|
||||
/// <param name="array">Array</param>
|
||||
/// <returns>True if null</returns>
|
||||
public static bool ArrayIsNullOrEmpty(byte[] array) => array?.All(b => b == 0x00) != false;
|
||||
}
|
||||
@@ -33,292 +33,291 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Aaru.Helpers
|
||||
namespace Aaru.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Converts base data types to an array of bytes, and an array of bytes to base data types. All info taken from
|
||||
/// the meta data of System.BitConverter. This implementation allows for Endianness consideration.
|
||||
/// </summary>
|
||||
public static class BigEndianBitConverter
|
||||
{
|
||||
/// <summary>Converts the specified double-precision floating point number to a 64-bit signed integer.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>A 64-bit signed integer whose value is equivalent to value.</returns>
|
||||
/// <exception cref="NotImplementedException">It is not currently implemented</exception>
|
||||
public static long DoubleToInt64Bits(double value) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>Returns the specified Boolean value as an array of bytes.</summary>
|
||||
/// <param name="value">A Boolean value.</param>
|
||||
/// <returns>An array of bytes with length 1.</returns>
|
||||
public static byte[] GetBytes(bool value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified Unicode character value as an array of bytes.</summary>
|
||||
/// <param name="value">A character to convert.</param>
|
||||
/// <returns>An array of bytes with length 2.</returns>
|
||||
public static byte[] GetBytes(char value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified double-precision floating point value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 8.</returns>
|
||||
public static byte[] GetBytes(double value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified single-precision floating point value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 4.</returns>
|
||||
public static byte[] GetBytes(float value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified 32-bit signed integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 4.</returns>
|
||||
public static byte[] GetBytes(int value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified 64-bit signed integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 8.</returns>
|
||||
public static byte[] GetBytes(long value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified 16-bit signed integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 2.</returns>
|
||||
public static byte[] GetBytes(short value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified 32-bit unsigned integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 4.</returns>
|
||||
public static byte[] GetBytes(uint value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified 64-bit unsigned integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 8.</returns>
|
||||
public static byte[] GetBytes(ulong value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified 16-bit unsigned integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 2.</returns>
|
||||
public static byte[] GetBytes(ushort value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Converts the specified 64-bit signed integer to a double-precision floating point number.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>A double-precision floating point number whose value is equivalent to value.</returns>
|
||||
public static double Int64BitsToDouble(long value) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>Returns a Boolean value converted from one byte at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>true if the byte at <see cref="startIndex" /> in value is nonzero; otherwise, false.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static bool ToBoolean(byte[] value, int startIndex) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>Returns a Unicode character converted from two bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A character formed by two bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException"><see cref="startIndex" /> equals the length of value minus 1.</exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static char ToChar(byte[] value, int startIndex) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Converts base data types to an array of bytes, and an array of bytes to base data types. All info taken from
|
||||
/// the meta data of System.BitConverter. This implementation allows for Endianness consideration.
|
||||
/// Returns a double-precision floating point number converted from eight bytes at a specified position in a byte
|
||||
/// array.
|
||||
/// </summary>
|
||||
public static class BigEndianBitConverter
|
||||
{
|
||||
/// <summary>Converts the specified double-precision floating point number to a 64-bit signed integer.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>A 64-bit signed integer whose value is equivalent to value.</returns>
|
||||
/// <exception cref="NotImplementedException">It is not currently implemented</exception>
|
||||
public static long DoubleToInt64Bits(double value) => throw new NotImplementedException();
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A double precision floating point number formed by eight bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// <see cref="startIndex" /> is greater than or equal to the length of value
|
||||
/// minus 7, and is less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static double ToDouble(byte[] value, int startIndex) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>Returns the specified Boolean value as an array of bytes.</summary>
|
||||
/// <param name="value">A Boolean value.</param>
|
||||
/// <returns>An array of bytes with length 1.</returns>
|
||||
public static byte[] GetBytes(bool value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
/// <summary>Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 16-bit signed integer formed by two bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException"><see cref="startIndex" /> equals the length of value minus 1.</exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static short ToInt16(byte[] value, int startIndex) =>
|
||||
BitConverter.ToInt16(value.Reverse().ToArray(), value.Length - sizeof(short) - startIndex);
|
||||
|
||||
/// <summary>Returns the specified Unicode character value as an array of bytes.</summary>
|
||||
/// <param name="value">A character to convert.</param>
|
||||
/// <returns>An array of bytes with length 2.</returns>
|
||||
public static byte[] GetBytes(char value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
/// <summary>Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 32-bit signed integer formed by four bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// <see cref="startIndex" /> is greater than or equal to the length of value
|
||||
/// minus 3, and is less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static int ToInt32(byte[] value, int startIndex) =>
|
||||
BitConverter.ToInt32(value.Reverse().ToArray(), value.Length - sizeof(int) - startIndex);
|
||||
|
||||
/// <summary>Returns the specified double-precision floating point value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 8.</returns>
|
||||
public static byte[] GetBytes(double value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
/// <summary>Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 64-bit signed integer formed by eight bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// <see cref="startIndex" /> is greater than or equal to the length of value
|
||||
/// minus 7, and is less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static long ToInt64(byte[] value, int startIndex) =>
|
||||
BitConverter.ToInt64(value.Reverse().ToArray(), value.Length - sizeof(long) - startIndex);
|
||||
|
||||
/// <summary>Returns the specified single-precision floating point value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 4.</returns>
|
||||
public static byte[] GetBytes(float value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
/// <summary>
|
||||
/// Returns a single-precision floating point number converted from four bytes at a specified position in a byte
|
||||
/// array.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A single-precision floating point number formed by four bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// <see cref="startIndex" /> is greater than or equal to the length of value
|
||||
/// minus 3, and is less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static float ToSingle(byte[] value, int startIndex) =>
|
||||
BitConverter.ToSingle(value.Reverse().ToArray(), value.Length - sizeof(float) - startIndex);
|
||||
|
||||
/// <summary>Returns the specified 32-bit signed integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 4.</returns>
|
||||
public static byte[] GetBytes(int value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
/// <summary>
|
||||
/// Converts the numeric value of each element of a specified array of bytes to its equivalent hexadecimal string
|
||||
/// representation.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <returns>
|
||||
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
|
||||
/// element in value; for example, "7F-2C-4A".
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
public static string ToString(byte[] value) => BitConverter.ToString(value.Reverse().ToArray());
|
||||
|
||||
/// <summary>Returns the specified 64-bit signed integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 8.</returns>
|
||||
public static byte[] GetBytes(long value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
/// <summary>
|
||||
/// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
|
||||
/// string representation.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>
|
||||
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
|
||||
/// element in a subarray of value; for example, "7F-2C-4A".
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static string ToString(byte[] value, int startIndex) =>
|
||||
BitConverter.ToString(value.Reverse().ToArray(), startIndex);
|
||||
|
||||
/// <summary>Returns the specified 16-bit signed integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 2.</returns>
|
||||
public static byte[] GetBytes(short value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
/// <summary>
|
||||
/// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
|
||||
/// string representation.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <param name="length">The number of array elements in value to convert.</param>
|
||||
/// <returns>
|
||||
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
|
||||
/// element in a subarray of value; for example, "7F-2C-4A".
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex or length is less than zero. -or- startIndex is greater
|
||||
/// than zero and is greater than or equal to the length of value.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// The combination of startIndex and length does not specify a position within
|
||||
/// value; that is, the startIndex parameter is greater than the length of value minus the length parameter.
|
||||
/// </exception>
|
||||
public static string ToString(byte[] value, int startIndex, int length) =>
|
||||
BitConverter.ToString(value.Reverse().ToArray(), startIndex, length);
|
||||
|
||||
/// <summary>Returns the specified 32-bit unsigned integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 4.</returns>
|
||||
public static byte[] GetBytes(uint value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
/// <summary>Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">The array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 16-bit unsigned integer formed by two bytes beginning at startIndex.</returns>
|
||||
/// <exception cref="System.ArgumentException">startIndex equals the length of value minus 1.</exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static ushort ToUInt16(byte[] value, int startIndex) =>
|
||||
BitConverter.ToUInt16(value.Reverse().ToArray(), value.Length - sizeof(ushort) - startIndex);
|
||||
|
||||
/// <summary>Returns the specified 64-bit unsigned integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 8.</returns>
|
||||
public static byte[] GetBytes(ulong value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
/// <summary>Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 32-bit unsigned integer formed by four bytes beginning at startIndex.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// startIndex is greater than or equal to the length of value minus 3, and is
|
||||
/// less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static uint ToUInt32(byte[] value, int startIndex) =>
|
||||
BitConverter.ToUInt32(value.Reverse().ToArray(), value.Length - sizeof(uint) - startIndex);
|
||||
|
||||
/// <summary>Returns the specified 16-bit unsigned integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 2.</returns>
|
||||
public static byte[] GetBytes(ushort value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
/// <summary>Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 64-bit unsigned integer formed by the eight bytes beginning at startIndex.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// startIndex is greater than or equal to the length of value minus 7, and is
|
||||
/// less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static ulong ToUInt64(byte[] value, int startIndex) =>
|
||||
BitConverter.ToUInt64(value.Reverse().ToArray(), value.Length - sizeof(ulong) - startIndex);
|
||||
|
||||
/// <summary>Converts the specified 64-bit signed integer to a double-precision floating point number.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>A double-precision floating point number whose value is equivalent to value.</returns>
|
||||
public static double Int64BitsToDouble(long value) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>Returns a Boolean value converted from one byte at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>true if the byte at <see cref="startIndex" /> in value is nonzero; otherwise, false.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static bool ToBoolean(byte[] value, int startIndex) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>Returns a Unicode character converted from two bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A character formed by two bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException"><see cref="startIndex" /> equals the length of value minus 1.</exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static char ToChar(byte[] value, int startIndex) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a double-precision floating point number converted from eight bytes at a specified position in a byte
|
||||
/// array.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A double precision floating point number formed by eight bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// <see cref="startIndex" /> is greater than or equal to the length of value
|
||||
/// minus 7, and is less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static double ToDouble(byte[] value, int startIndex) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 16-bit signed integer formed by two bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException"><see cref="startIndex" /> equals the length of value minus 1.</exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static short ToInt16(byte[] value, int startIndex) =>
|
||||
BitConverter.ToInt16(value.Reverse().ToArray(), value.Length - sizeof(short) - startIndex);
|
||||
|
||||
/// <summary>Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 32-bit signed integer formed by four bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// <see cref="startIndex" /> is greater than or equal to the length of value
|
||||
/// minus 3, and is less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static int ToInt32(byte[] value, int startIndex) =>
|
||||
BitConverter.ToInt32(value.Reverse().ToArray(), value.Length - sizeof(int) - startIndex);
|
||||
|
||||
/// <summary>Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 64-bit signed integer formed by eight bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// <see cref="startIndex" /> is greater than or equal to the length of value
|
||||
/// minus 7, and is less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static long ToInt64(byte[] value, int startIndex) =>
|
||||
BitConverter.ToInt64(value.Reverse().ToArray(), value.Length - sizeof(long) - startIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a single-precision floating point number converted from four bytes at a specified position in a byte
|
||||
/// array.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A single-precision floating point number formed by four bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// <see cref="startIndex" /> is greater than or equal to the length of value
|
||||
/// minus 3, and is less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static float ToSingle(byte[] value, int startIndex) =>
|
||||
BitConverter.ToSingle(value.Reverse().ToArray(), value.Length - sizeof(float) - startIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the numeric value of each element of a specified array of bytes to its equivalent hexadecimal string
|
||||
/// representation.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <returns>
|
||||
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
|
||||
/// element in value; for example, "7F-2C-4A".
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
public static string ToString(byte[] value) => BitConverter.ToString(value.Reverse().ToArray());
|
||||
|
||||
/// <summary>
|
||||
/// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
|
||||
/// string representation.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>
|
||||
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
|
||||
/// element in a subarray of value; for example, "7F-2C-4A".
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static string ToString(byte[] value, int startIndex) =>
|
||||
BitConverter.ToString(value.Reverse().ToArray(), startIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
|
||||
/// string representation.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <param name="length">The number of array elements in value to convert.</param>
|
||||
/// <returns>
|
||||
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
|
||||
/// element in a subarray of value; for example, "7F-2C-4A".
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex or length is less than zero. -or- startIndex is greater
|
||||
/// than zero and is greater than or equal to the length of value.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// The combination of startIndex and length does not specify a position within
|
||||
/// value; that is, the startIndex parameter is greater than the length of value minus the length parameter.
|
||||
/// </exception>
|
||||
public static string ToString(byte[] value, int startIndex, int length) =>
|
||||
BitConverter.ToString(value.Reverse().ToArray(), startIndex, length);
|
||||
|
||||
/// <summary>Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">The array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 16-bit unsigned integer formed by two bytes beginning at startIndex.</returns>
|
||||
/// <exception cref="System.ArgumentException">startIndex equals the length of value minus 1.</exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static ushort ToUInt16(byte[] value, int startIndex) =>
|
||||
BitConverter.ToUInt16(value.Reverse().ToArray(), value.Length - sizeof(ushort) - startIndex);
|
||||
|
||||
/// <summary>Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 32-bit unsigned integer formed by four bytes beginning at startIndex.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// startIndex is greater than or equal to the length of value minus 3, and is
|
||||
/// less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static uint ToUInt32(byte[] value, int startIndex) =>
|
||||
BitConverter.ToUInt32(value.Reverse().ToArray(), value.Length - sizeof(uint) - startIndex);
|
||||
|
||||
/// <summary>Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 64-bit unsigned integer formed by the eight bytes beginning at startIndex.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// startIndex is greater than or equal to the length of value minus 7, and is
|
||||
/// less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static ulong ToUInt64(byte[] value, int startIndex) =>
|
||||
BitConverter.ToUInt64(value.Reverse().ToArray(), value.Length - sizeof(ulong) - startIndex);
|
||||
|
||||
/// <summary>Converts a big endian byte array representation of a GUID into the .NET Guid structure</summary>
|
||||
/// <param name="value">Byte array containing a GUID in big endian</param>
|
||||
/// <param name="startIndex">Start of the byte array to process</param>
|
||||
/// <returns>Processed Guid</returns>
|
||||
public static Guid ToGuid(byte[] value, int startIndex) => new Guid(ToUInt32(value, 0 + startIndex),
|
||||
ToUInt16(value, 4 + startIndex),
|
||||
ToUInt16(value, 6 + startIndex),
|
||||
value[8 + startIndex + 0],
|
||||
value[8 + startIndex + 1],
|
||||
value[8 + startIndex + 2],
|
||||
value[8 + startIndex + 3],
|
||||
value[8 + startIndex + 5],
|
||||
value[8 + startIndex + 5],
|
||||
value[8 + startIndex + 6],
|
||||
value[8 + startIndex + 7]);
|
||||
}
|
||||
/// <summary>Converts a big endian byte array representation of a GUID into the .NET Guid structure</summary>
|
||||
/// <param name="value">Byte array containing a GUID in big endian</param>
|
||||
/// <param name="startIndex">Start of the byte array to process</param>
|
||||
/// <returns>Processed Guid</returns>
|
||||
public static Guid ToGuid(byte[] value, int startIndex) => new Guid(ToUInt32(value, 0 + startIndex),
|
||||
ToUInt16(value, 4 + startIndex),
|
||||
ToUInt16(value, 6 + startIndex),
|
||||
value[8 + startIndex + 0],
|
||||
value[8 + startIndex + 1],
|
||||
value[8 + startIndex + 2],
|
||||
value[8 + startIndex + 3],
|
||||
value[8 + startIndex + 5],
|
||||
value[8 + startIndex + 5],
|
||||
value[8 + startIndex + 6],
|
||||
value[8 + startIndex + 7]);
|
||||
}
|
||||
21
BitEndian.cs
21
BitEndian.cs
@@ -36,16 +36,15 @@
|
||||
// Copyright © 2011-2022 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace Aaru.Helpers
|
||||
namespace Aaru.Helpers;
|
||||
|
||||
/// <summary>Describes the endianness of bits on a data structure</summary>
|
||||
public enum BitEndian
|
||||
{
|
||||
/// <summary>Describes the endianness of bits on a data structure</summary>
|
||||
public enum BitEndian
|
||||
{
|
||||
/// <summary>Little-endian, or least significant bit</summary>
|
||||
Little,
|
||||
/// <summary>Big-endian, or most significant bit</summary>
|
||||
Big,
|
||||
/// <summary>PDP-11 endian, little endian except for 32-bit integers where the 16 halves are swapped between them</summary>
|
||||
Pdp
|
||||
}
|
||||
/// <summary>Little-endian, or least significant bit</summary>
|
||||
Little,
|
||||
/// <summary>Big-endian, or most significant bit</summary>
|
||||
Big,
|
||||
/// <summary>PDP-11 endian, little endian except for 32-bit integers where the 16 halves are swapped between them</summary>
|
||||
Pdp
|
||||
}
|
||||
29
CHS.cs
29
CHS.cs
@@ -30,20 +30,19 @@
|
||||
// Copyright © 2011-2022 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace Aaru.Helpers
|
||||
namespace Aaru.Helpers;
|
||||
|
||||
/// <summary>Helper operations to work with CHS values</summary>
|
||||
public static class CHS
|
||||
{
|
||||
/// <summary>Helper operations to work with CHS values</summary>
|
||||
public static class CHS
|
||||
{
|
||||
/// <summary>Converts a CHS position to a LBA one</summary>
|
||||
/// <param name="cyl">Cylinder</param>
|
||||
/// <param name="head">Head</param>
|
||||
/// <param name="sector">Sector</param>
|
||||
/// <param name="maxHead">Number of heads</param>
|
||||
/// <param name="maxSector">Number of sectors per track</param>
|
||||
/// <returns></returns>
|
||||
public static uint ToLBA(uint cyl, uint head, uint sector, uint maxHead, uint maxSector) =>
|
||||
maxHead == 0 || maxSector == 0 ? (((cyl * 16) + head) * 63) + sector - 1
|
||||
: (((cyl * maxHead) + head) * maxSector) + sector - 1;
|
||||
}
|
||||
/// <summary>Converts a CHS position to a LBA one</summary>
|
||||
/// <param name="cyl">Cylinder</param>
|
||||
/// <param name="head">Head</param>
|
||||
/// <param name="sector">Sector</param>
|
||||
/// <param name="maxHead">Number of heads</param>
|
||||
/// <param name="maxSector">Number of sectors per track</param>
|
||||
/// <returns></returns>
|
||||
public static uint ToLBA(uint cyl, uint head, uint sector, uint maxHead, uint maxSector) =>
|
||||
maxHead == 0 || maxSector == 0 ? (((cyl * 16) + head) * 63) + sector - 1
|
||||
: (((cyl * maxHead) + head) * maxSector) + sector - 1;
|
||||
}
|
||||
@@ -30,43 +30,42 @@
|
||||
// Copyright © 2011-2022 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace Aaru.Helpers
|
||||
namespace Aaru.Helpers;
|
||||
|
||||
public static partial class ArrayHelpers
|
||||
{
|
||||
public static partial class ArrayHelpers
|
||||
/// <summary>Compares two byte arrays</summary>
|
||||
/// <param name="different"><c>true</c> if they are different in any way</param>
|
||||
/// <param name="sameSize"><c>true</c> if they have the same size</param>
|
||||
/// <param name="compareArray1">Left array</param>
|
||||
/// <param name="compareArray2">Right array</param>
|
||||
public static void CompareBytes(out bool different, out bool sameSize, byte[] compareArray1,
|
||||
byte[] compareArray2)
|
||||
{
|
||||
/// <summary>Compares two byte arrays</summary>
|
||||
/// <param name="different"><c>true</c> if they are different in any way</param>
|
||||
/// <param name="sameSize"><c>true</c> if they have the same size</param>
|
||||
/// <param name="compareArray1">Left array</param>
|
||||
/// <param name="compareArray2">Right array</param>
|
||||
public static void CompareBytes(out bool different, out bool sameSize, byte[] compareArray1,
|
||||
byte[] compareArray2)
|
||||
different = false;
|
||||
sameSize = true;
|
||||
|
||||
long leastBytes;
|
||||
|
||||
if(compareArray1.LongLength < compareArray2.LongLength)
|
||||
{
|
||||
different = false;
|
||||
sameSize = true;
|
||||
|
||||
long leastBytes;
|
||||
|
||||
if(compareArray1.LongLength < compareArray2.LongLength)
|
||||
{
|
||||
sameSize = false;
|
||||
leastBytes = compareArray1.LongLength;
|
||||
}
|
||||
else if(compareArray1.LongLength > compareArray2.LongLength)
|
||||
{
|
||||
sameSize = false;
|
||||
leastBytes = compareArray2.LongLength;
|
||||
}
|
||||
else
|
||||
leastBytes = compareArray1.LongLength;
|
||||
|
||||
for(long i = 0; i < leastBytes; i++)
|
||||
if(compareArray1[i] != compareArray2[i])
|
||||
{
|
||||
different = true;
|
||||
|
||||
return;
|
||||
}
|
||||
sameSize = false;
|
||||
leastBytes = compareArray1.LongLength;
|
||||
}
|
||||
else if(compareArray1.LongLength > compareArray2.LongLength)
|
||||
{
|
||||
sameSize = false;
|
||||
leastBytes = compareArray2.LongLength;
|
||||
}
|
||||
else
|
||||
leastBytes = compareArray1.LongLength;
|
||||
|
||||
for(long i = 0; i < leastBytes; i++)
|
||||
if(compareArray1[i] != compareArray2[i])
|
||||
{
|
||||
different = true;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
CountBits.cs
27
CountBits.cs
@@ -30,20 +30,19 @@
|
||||
// Copyright © 2011-2022 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace Aaru.Helpers
|
||||
{
|
||||
/// <summary>Helper operations to count bits</summary>
|
||||
public static class CountBits
|
||||
{
|
||||
/// <summary>Counts the number of bits set to <c>true</c> in a number</summary>
|
||||
/// <param name="number">Number</param>
|
||||
/// <returns>Bits set to <c>true</c></returns>
|
||||
public static int Count(uint number)
|
||||
{
|
||||
number -= (number >> 1) & 0x55555555;
|
||||
number = (number & 0x33333333) + ((number >> 2) & 0x33333333);
|
||||
namespace Aaru.Helpers;
|
||||
|
||||
return (int)((((number + (number >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24);
|
||||
}
|
||||
/// <summary>Helper operations to count bits</summary>
|
||||
public static class CountBits
|
||||
{
|
||||
/// <summary>Counts the number of bits set to <c>true</c> in a number</summary>
|
||||
/// <param name="number">Number</param>
|
||||
/// <returns>Bits set to <c>true</c></returns>
|
||||
public static int Count(uint number)
|
||||
{
|
||||
number -= (number >> 1) & 0x55555555;
|
||||
number = (number & 0x33333333) + ((number >> 2) & 0x33333333);
|
||||
|
||||
return (int)((((number + (number >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24);
|
||||
}
|
||||
}
|
||||
655
DateHandlers.cs
655
DateHandlers.cs
@@ -34,356 +34,355 @@ using System;
|
||||
using System.Text;
|
||||
using Aaru.Console;
|
||||
|
||||
namespace Aaru.Helpers
|
||||
namespace Aaru.Helpers;
|
||||
|
||||
/// <summary>Helper operations for timestamp management (date and time)</summary>
|
||||
public static class DateHandlers
|
||||
{
|
||||
/// <summary>Helper operations for timestamp management (date and time)</summary>
|
||||
public static class DateHandlers
|
||||
static readonly DateTime _lisaEpoch = new DateTime(1901, 1, 1, 0, 0, 0);
|
||||
static readonly DateTime _macEpoch = new DateTime(1904, 1, 1, 0, 0, 0);
|
||||
static readonly DateTime _unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0);
|
||||
/// <summary>Day 0 of Julian Date system</summary>
|
||||
static readonly DateTime _julianEpoch = new DateTime(1858, 11, 17, 0, 0, 0);
|
||||
static readonly DateTime _amigaEpoch = new DateTime(1978, 1, 1, 0, 0, 0);
|
||||
|
||||
/// <summary>Converts a Macintosh timestamp to a .NET DateTime</summary>
|
||||
/// <param name="macTimeStamp">Macintosh timestamp (seconds since 1st Jan. 1904)</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime MacToDateTime(ulong macTimeStamp) => _macEpoch.AddTicks((long)(macTimeStamp * 10000000));
|
||||
|
||||
/// <summary>Converts a Lisa timestamp to a .NET DateTime</summary>
|
||||
/// <param name="lisaTimeStamp">Lisa timestamp (seconds since 1st Jan. 1901)</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime LisaToDateTime(uint lisaTimeStamp) => _lisaEpoch.AddSeconds(lisaTimeStamp);
|
||||
|
||||
/// <summary>Converts a UNIX timestamp to a .NET DateTime</summary>
|
||||
/// <param name="unixTimeStamp">UNIX timestamp (seconds since 1st Jan. 1970)</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime UnixToDateTime(int unixTimeStamp) => _unixEpoch.AddSeconds(unixTimeStamp);
|
||||
|
||||
/// <summary>Converts a UNIX timestamp to a .NET DateTime</summary>
|
||||
/// <param name="unixTimeStamp">UNIX timestamp (seconds since 1st Jan. 1970)</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime UnixToDateTime(long unixTimeStamp) => _unixEpoch.AddSeconds(unixTimeStamp);
|
||||
|
||||
/// <summary>Converts a UNIX timestamp to a .NET DateTime</summary>
|
||||
/// <param name="unixTimeStamp">UNIX timestamp (seconds since 1st Jan. 1970)</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime UnixUnsignedToDateTime(uint unixTimeStamp) => _unixEpoch.AddSeconds(unixTimeStamp);
|
||||
|
||||
/// <summary>Converts a UNIX timestamp to a .NET DateTime</summary>
|
||||
/// <param name="seconds">Seconds since 1st Jan. 1970)</param>
|
||||
/// <param name="nanoseconds">Nanoseconds</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime UnixUnsignedToDateTime(uint seconds, uint nanoseconds) =>
|
||||
_unixEpoch.AddSeconds(seconds).AddTicks((long)nanoseconds / 100);
|
||||
|
||||
/// <summary>Converts a UNIX timestamp to a .NET DateTime</summary>
|
||||
/// <param name="unixTimeStamp">UNIX timestamp (seconds since 1st Jan. 1970)</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime UnixUnsignedToDateTime(ulong unixTimeStamp) => _unixEpoch.AddSeconds(unixTimeStamp);
|
||||
|
||||
/// <summary>Converts a High Sierra Format timestamp to a .NET DateTime</summary>
|
||||
/// <param name="vdDateTime">High Sierra Format timestamp</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime HighSierraToDateTime(byte[] vdDateTime)
|
||||
{
|
||||
static readonly DateTime _lisaEpoch = new DateTime(1901, 1, 1, 0, 0, 0);
|
||||
static readonly DateTime _macEpoch = new DateTime(1904, 1, 1, 0, 0, 0);
|
||||
static readonly DateTime _unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0);
|
||||
/// <summary>Day 0 of Julian Date system</summary>
|
||||
static readonly DateTime _julianEpoch = new DateTime(1858, 11, 17, 0, 0, 0);
|
||||
static readonly DateTime _amigaEpoch = new DateTime(1978, 1, 1, 0, 0, 0);
|
||||
byte[] isoTime = new byte[17];
|
||||
Array.Copy(vdDateTime, 0, isoTime, 0, 16);
|
||||
|
||||
/// <summary>Converts a Macintosh timestamp to a .NET DateTime</summary>
|
||||
/// <param name="macTimeStamp">Macintosh timestamp (seconds since 1st Jan. 1904)</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime MacToDateTime(ulong macTimeStamp) => _macEpoch.AddTicks((long)(macTimeStamp * 10000000));
|
||||
return Iso9660ToDateTime(isoTime);
|
||||
}
|
||||
|
||||
/// <summary>Converts a Lisa timestamp to a .NET DateTime</summary>
|
||||
/// <param name="lisaTimeStamp">Lisa timestamp (seconds since 1st Jan. 1901)</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime LisaToDateTime(uint lisaTimeStamp) => _lisaEpoch.AddSeconds(lisaTimeStamp);
|
||||
// TODO: Timezone
|
||||
/// <summary>Converts an ISO9660 timestamp to a .NET DateTime</summary>
|
||||
/// <param name="vdDateTime">ISO9660 timestamp</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime Iso9660ToDateTime(byte[] vdDateTime)
|
||||
{
|
||||
byte[] twoCharValue = new byte[2];
|
||||
byte[] fourCharValue = new byte[4];
|
||||
|
||||
/// <summary>Converts a UNIX timestamp to a .NET DateTime</summary>
|
||||
/// <param name="unixTimeStamp">UNIX timestamp (seconds since 1st Jan. 1970)</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime UnixToDateTime(int unixTimeStamp) => _unixEpoch.AddSeconds(unixTimeStamp);
|
||||
fourCharValue[0] = vdDateTime[0];
|
||||
fourCharValue[1] = vdDateTime[1];
|
||||
fourCharValue[2] = vdDateTime[2];
|
||||
fourCharValue[3] = vdDateTime[3];
|
||||
|
||||
/// <summary>Converts a UNIX timestamp to a .NET DateTime</summary>
|
||||
/// <param name="unixTimeStamp">UNIX timestamp (seconds since 1st Jan. 1970)</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime UnixToDateTime(long unixTimeStamp) => _unixEpoch.AddSeconds(unixTimeStamp);
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler", "year = \"{0}\"",
|
||||
StringHandlers.CToString(fourCharValue, Encoding.ASCII));
|
||||
|
||||
/// <summary>Converts a UNIX timestamp to a .NET DateTime</summary>
|
||||
/// <param name="unixTimeStamp">UNIX timestamp (seconds since 1st Jan. 1970)</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime UnixUnsignedToDateTime(uint unixTimeStamp) => _unixEpoch.AddSeconds(unixTimeStamp);
|
||||
if(!int.TryParse(StringHandlers.CToString(fourCharValue, Encoding.ASCII), out int year))
|
||||
year = 0;
|
||||
|
||||
/// <summary>Converts a UNIX timestamp to a .NET DateTime</summary>
|
||||
/// <param name="seconds">Seconds since 1st Jan. 1970)</param>
|
||||
/// <param name="nanoseconds">Nanoseconds</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime UnixUnsignedToDateTime(uint seconds, uint nanoseconds) =>
|
||||
_unixEpoch.AddSeconds(seconds).AddTicks((long)nanoseconds / 100);
|
||||
twoCharValue[0] = vdDateTime[4];
|
||||
twoCharValue[1] = vdDateTime[5];
|
||||
|
||||
/// <summary>Converts a UNIX timestamp to a .NET DateTime</summary>
|
||||
/// <param name="unixTimeStamp">UNIX timestamp (seconds since 1st Jan. 1970)</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime UnixUnsignedToDateTime(ulong unixTimeStamp) => _unixEpoch.AddSeconds(unixTimeStamp);
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler", "month = \"{0}\"",
|
||||
StringHandlers.CToString(twoCharValue, Encoding.ASCII));
|
||||
|
||||
/// <summary>Converts a High Sierra Format timestamp to a .NET DateTime</summary>
|
||||
/// <param name="vdDateTime">High Sierra Format timestamp</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime HighSierraToDateTime(byte[] vdDateTime)
|
||||
if(!int.TryParse(StringHandlers.CToString(twoCharValue, Encoding.ASCII), out int month))
|
||||
month = 0;
|
||||
|
||||
twoCharValue[0] = vdDateTime[6];
|
||||
twoCharValue[1] = vdDateTime[7];
|
||||
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler", "day = \"{0}\"",
|
||||
StringHandlers.CToString(twoCharValue, Encoding.ASCII));
|
||||
|
||||
if(!int.TryParse(StringHandlers.CToString(twoCharValue, Encoding.ASCII), out int day))
|
||||
day = 0;
|
||||
|
||||
twoCharValue[0] = vdDateTime[8];
|
||||
twoCharValue[1] = vdDateTime[9];
|
||||
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler", "hour = \"{0}\"",
|
||||
StringHandlers.CToString(twoCharValue, Encoding.ASCII));
|
||||
|
||||
if(!int.TryParse(StringHandlers.CToString(twoCharValue, Encoding.ASCII), out int hour))
|
||||
hour = 0;
|
||||
|
||||
twoCharValue[0] = vdDateTime[10];
|
||||
twoCharValue[1] = vdDateTime[11];
|
||||
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler", "minute = \"{0}\"",
|
||||
StringHandlers.CToString(twoCharValue, Encoding.ASCII));
|
||||
|
||||
if(!int.TryParse(StringHandlers.CToString(twoCharValue, Encoding.ASCII), out int minute))
|
||||
minute = 0;
|
||||
|
||||
twoCharValue[0] = vdDateTime[12];
|
||||
twoCharValue[1] = vdDateTime[13];
|
||||
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler", "second = \"{0}\"",
|
||||
StringHandlers.CToString(twoCharValue, Encoding.ASCII));
|
||||
|
||||
if(!int.TryParse(StringHandlers.CToString(twoCharValue, Encoding.ASCII), out int second))
|
||||
second = 0;
|
||||
|
||||
twoCharValue[0] = vdDateTime[14];
|
||||
twoCharValue[1] = vdDateTime[15];
|
||||
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler", "hundredths = \"{0}\"",
|
||||
StringHandlers.CToString(twoCharValue, Encoding.ASCII));
|
||||
|
||||
if(!int.TryParse(StringHandlers.CToString(twoCharValue, Encoding.ASCII), out int hundredths))
|
||||
hundredths = 0;
|
||||
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler",
|
||||
"decodedDT = new DateTime({0}, {1}, {2}, {3}, {4}, {5}, {6}, DateTimeKind.Unspecified);",
|
||||
year, month, day, hour, minute, second, hundredths * 10);
|
||||
|
||||
sbyte difference = (sbyte)vdDateTime[16];
|
||||
|
||||
var decodedDt = new DateTime(year, month, day, hour, minute, second, hundredths * 10, DateTimeKind.Utc);
|
||||
|
||||
return decodedDt.AddMinutes(difference * -15);
|
||||
}
|
||||
|
||||
/// <summary>Converts a VMS timestamp to a .NET DateTime</summary>
|
||||
/// <param name="vmsDate">VMS timestamp (tenths of microseconds since day 0 of the Julian Date)</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
/// <remarks>C# works in UTC, VMS on Julian Date, some displacement may occur on disks created outside UTC</remarks>
|
||||
public static DateTime VmsToDateTime(ulong vmsDate)
|
||||
{
|
||||
double delta = vmsDate * 0.0001; // Tenths of microseconds to milliseconds, will lose some detail
|
||||
|
||||
return _julianEpoch.AddMilliseconds(delta);
|
||||
}
|
||||
|
||||
/// <summary>Converts an Amiga timestamp to a .NET DateTime</summary>
|
||||
/// <param name="days">Days since the 1st Jan. 1978</param>
|
||||
/// <param name="minutes">Minutes since o'clock</param>
|
||||
/// <param name="ticks">Ticks</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime AmigaToDateTime(uint days, uint minutes, uint ticks)
|
||||
{
|
||||
DateTime temp = _amigaEpoch.AddDays(days);
|
||||
temp = temp.AddMinutes(minutes);
|
||||
|
||||
return temp.AddMilliseconds(ticks * 20);
|
||||
}
|
||||
|
||||
/// <summary>Converts an UCSD Pascal timestamp to a .NET DateTime</summary>
|
||||
/// <param name="dateRecord">UCSD Pascal timestamp</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime UcsdPascalToDateTime(short dateRecord)
|
||||
{
|
||||
int year = ((dateRecord & 0xFE00) >> 9) + 1900;
|
||||
int day = (dateRecord & 0x01F0) >> 4;
|
||||
int month = dateRecord & 0x000F;
|
||||
|
||||
AaruConsole.DebugWriteLine("UCSDPascalToDateTime handler",
|
||||
"dateRecord = 0x{0:X4}, year = {1}, month = {2}, day = {3}", dateRecord, year,
|
||||
month, day);
|
||||
|
||||
return new DateTime(year, month, day);
|
||||
}
|
||||
|
||||
/// <summary>Converts a DOS timestamp to a .NET DateTime</summary>
|
||||
/// <param name="date">Date</param>
|
||||
/// <param name="time">Time</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime DosToDateTime(ushort date, ushort time)
|
||||
{
|
||||
int year = ((date & 0xFE00) >> 9) + 1980;
|
||||
int month = (date & 0x1E0) >> 5;
|
||||
int day = date & 0x1F;
|
||||
int hour = (time & 0xF800) >> 11;
|
||||
int minute = (time & 0x7E0) >> 5;
|
||||
int second = (time & 0x1F) * 2;
|
||||
|
||||
AaruConsole.DebugWriteLine("DOSToDateTime handler", "date = 0x{0:X4}, year = {1}, month = {2}, day = {3}",
|
||||
date, year, month, day);
|
||||
|
||||
AaruConsole.DebugWriteLine("DOSToDateTime handler",
|
||||
"time = 0x{0:X4}, hour = {1}, minute = {2}, second = {3}", time, hour, minute,
|
||||
second);
|
||||
|
||||
DateTime dosDate;
|
||||
|
||||
try
|
||||
{
|
||||
byte[] isoTime = new byte[17];
|
||||
Array.Copy(vdDateTime, 0, isoTime, 0, 16);
|
||||
|
||||
return Iso9660ToDateTime(isoTime);
|
||||
dosDate = new DateTime(year, month, day, hour, minute, second);
|
||||
}
|
||||
catch(ArgumentOutOfRangeException)
|
||||
{
|
||||
dosDate = new DateTime(1980, 1, 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
// TODO: Timezone
|
||||
/// <summary>Converts an ISO9660 timestamp to a .NET DateTime</summary>
|
||||
/// <param name="vdDateTime">ISO9660 timestamp</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime Iso9660ToDateTime(byte[] vdDateTime)
|
||||
return dosDate;
|
||||
}
|
||||
|
||||
/// <summary>Converts a CP/M timestamp to .NET DateTime</summary>
|
||||
/// <param name="timestamp">CP/M timestamp</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime CpmToDateTime(byte[] timestamp)
|
||||
{
|
||||
ushort days = BitConverter.ToUInt16(timestamp, 0);
|
||||
int hours = timestamp[2];
|
||||
int minutes = timestamp[3];
|
||||
|
||||
DateTime temp = _amigaEpoch.AddDays(days);
|
||||
temp = temp.AddHours(hours);
|
||||
temp = temp.AddMinutes(minutes);
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>Converts an ECMA timestamp to a .NET DateTime</summary>
|
||||
/// <param name="typeAndTimeZone">Timezone</param>
|
||||
/// <param name="year">Year</param>
|
||||
/// <param name="month">Month</param>
|
||||
/// <param name="day">Day</param>
|
||||
/// <param name="hour">Hour</param>
|
||||
/// <param name="minute">Minute</param>
|
||||
/// <param name="second">Second</param>
|
||||
/// <param name="centiseconds">Centiseconds</param>
|
||||
/// <param name="hundredsOfMicroseconds">Hundreds of microseconds</param>
|
||||
/// <param name="microseconds">Microseconds</param>
|
||||
/// <returns></returns>
|
||||
public static DateTime EcmaToDateTime(ushort typeAndTimeZone, short year, byte month, byte day, byte hour,
|
||||
byte minute, byte second, byte centiseconds, byte hundredsOfMicroseconds,
|
||||
byte microseconds)
|
||||
{
|
||||
byte specification = (byte)((typeAndTimeZone & 0xF000) >> 12);
|
||||
|
||||
long ticks = ((long)centiseconds * 100000) + ((long)hundredsOfMicroseconds * 1000) +
|
||||
((long)microseconds * 10);
|
||||
|
||||
if(specification == 0)
|
||||
return new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc).AddTicks(ticks);
|
||||
|
||||
ushort preOffset = (ushort)(typeAndTimeZone & 0xFFF);
|
||||
short offset;
|
||||
|
||||
if((preOffset & 0x800) == 0x800)
|
||||
offset = (short)(preOffset | 0xF000);
|
||||
else
|
||||
offset = (short)(preOffset & 0x7FF);
|
||||
|
||||
if(offset == -2047)
|
||||
return new DateTime(year, month, day, hour, minute, second, DateTimeKind.Unspecified).AddTicks(ticks);
|
||||
|
||||
if(offset < -1440 ||
|
||||
offset > 1440)
|
||||
offset = 0;
|
||||
|
||||
return new DateTimeOffset(year, month, day, hour, minute, second, new TimeSpan(0, offset, 0)).
|
||||
AddTicks(ticks).DateTime;
|
||||
}
|
||||
|
||||
/// <summary>Converts a Solaris high resolution timestamp to .NET DateTime</summary>
|
||||
/// <param name="hrTimeStamp">Solaris high resolution timestamp</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime UnixHrTimeToDateTime(ulong hrTimeStamp) =>
|
||||
_unixEpoch.AddTicks((long)(hrTimeStamp / 100));
|
||||
|
||||
/// <summary>Converts an OS-9 timestamp to .NET DateTime</summary>
|
||||
/// <param name="date">OS-9 timestamp</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime Os9ToDateTime(byte[] date)
|
||||
{
|
||||
if(date == null ||
|
||||
(date.Length != 3 && date.Length != 5))
|
||||
return DateTime.MinValue;
|
||||
|
||||
DateTime os9Date;
|
||||
|
||||
try
|
||||
{
|
||||
byte[] twoCharValue = new byte[2];
|
||||
byte[] fourCharValue = new byte[4];
|
||||
|
||||
fourCharValue[0] = vdDateTime[0];
|
||||
fourCharValue[1] = vdDateTime[1];
|
||||
fourCharValue[2] = vdDateTime[2];
|
||||
fourCharValue[3] = vdDateTime[3];
|
||||
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler", "year = \"{0}\"",
|
||||
StringHandlers.CToString(fourCharValue, Encoding.ASCII));
|
||||
|
||||
if(!int.TryParse(StringHandlers.CToString(fourCharValue, Encoding.ASCII), out int year))
|
||||
year = 0;
|
||||
|
||||
twoCharValue[0] = vdDateTime[4];
|
||||
twoCharValue[1] = vdDateTime[5];
|
||||
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler", "month = \"{0}\"",
|
||||
StringHandlers.CToString(twoCharValue, Encoding.ASCII));
|
||||
|
||||
if(!int.TryParse(StringHandlers.CToString(twoCharValue, Encoding.ASCII), out int month))
|
||||
month = 0;
|
||||
|
||||
twoCharValue[0] = vdDateTime[6];
|
||||
twoCharValue[1] = vdDateTime[7];
|
||||
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler", "day = \"{0}\"",
|
||||
StringHandlers.CToString(twoCharValue, Encoding.ASCII));
|
||||
|
||||
if(!int.TryParse(StringHandlers.CToString(twoCharValue, Encoding.ASCII), out int day))
|
||||
day = 0;
|
||||
|
||||
twoCharValue[0] = vdDateTime[8];
|
||||
twoCharValue[1] = vdDateTime[9];
|
||||
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler", "hour = \"{0}\"",
|
||||
StringHandlers.CToString(twoCharValue, Encoding.ASCII));
|
||||
|
||||
if(!int.TryParse(StringHandlers.CToString(twoCharValue, Encoding.ASCII), out int hour))
|
||||
hour = 0;
|
||||
|
||||
twoCharValue[0] = vdDateTime[10];
|
||||
twoCharValue[1] = vdDateTime[11];
|
||||
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler", "minute = \"{0}\"",
|
||||
StringHandlers.CToString(twoCharValue, Encoding.ASCII));
|
||||
|
||||
if(!int.TryParse(StringHandlers.CToString(twoCharValue, Encoding.ASCII), out int minute))
|
||||
minute = 0;
|
||||
|
||||
twoCharValue[0] = vdDateTime[12];
|
||||
twoCharValue[1] = vdDateTime[13];
|
||||
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler", "second = \"{0}\"",
|
||||
StringHandlers.CToString(twoCharValue, Encoding.ASCII));
|
||||
|
||||
if(!int.TryParse(StringHandlers.CToString(twoCharValue, Encoding.ASCII), out int second))
|
||||
second = 0;
|
||||
|
||||
twoCharValue[0] = vdDateTime[14];
|
||||
twoCharValue[1] = vdDateTime[15];
|
||||
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler", "hundredths = \"{0}\"",
|
||||
StringHandlers.CToString(twoCharValue, Encoding.ASCII));
|
||||
|
||||
if(!int.TryParse(StringHandlers.CToString(twoCharValue, Encoding.ASCII), out int hundredths))
|
||||
hundredths = 0;
|
||||
|
||||
AaruConsole.DebugWriteLine("ISO9600ToDateTime handler",
|
||||
"decodedDT = new DateTime({0}, {1}, {2}, {3}, {4}, {5}, {6}, DateTimeKind.Unspecified);",
|
||||
year, month, day, hour, minute, second, hundredths * 10);
|
||||
|
||||
sbyte difference = (sbyte)vdDateTime[16];
|
||||
|
||||
var decodedDt = new DateTime(year, month, day, hour, minute, second, hundredths * 10, DateTimeKind.Utc);
|
||||
|
||||
return decodedDt.AddMinutes(difference * -15);
|
||||
os9Date = date.Length == 5 ? new DateTime(1900 + date[0], date[1], date[2], date[3], date[4], 0)
|
||||
: new DateTime(1900 + date[0], date[1], date[2], 0, 0, 0);
|
||||
}
|
||||
catch(ArgumentOutOfRangeException)
|
||||
{
|
||||
os9Date = new DateTime(1900, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/// <summary>Converts a VMS timestamp to a .NET DateTime</summary>
|
||||
/// <param name="vmsDate">VMS timestamp (tenths of microseconds since day 0 of the Julian Date)</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
/// <remarks>C# works in UTC, VMS on Julian Date, some displacement may occur on disks created outside UTC</remarks>
|
||||
public static DateTime VmsToDateTime(ulong vmsDate)
|
||||
return os9Date;
|
||||
}
|
||||
|
||||
/// <summary>Converts a LIF timestamp to .NET DateTime</summary>
|
||||
/// <param name="date">LIF timestamp</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime LifToDateTime(byte[] date)
|
||||
{
|
||||
if(date == null ||
|
||||
date.Length != 6)
|
||||
return new DateTime(1970, 1, 1, 0, 0, 0);
|
||||
|
||||
return LifToDateTime(date[0], date[1], date[2], date[3], date[4], date[5]);
|
||||
}
|
||||
|
||||
/// <summary>Converts a LIF timestamp to .NET DateTime</summary>
|
||||
/// <param name="year">Yer</param>
|
||||
/// <param name="month">Month</param>
|
||||
/// <param name="day">Day</param>
|
||||
/// <param name="hour">Hour</param>
|
||||
/// <param name="minute">Minute</param>
|
||||
/// <param name="second">Second</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime LifToDateTime(byte year, byte month, byte day, byte hour, byte minute, byte second)
|
||||
{
|
||||
try
|
||||
{
|
||||
double delta = vmsDate * 0.0001; // Tenths of microseconds to milliseconds, will lose some detail
|
||||
int iyear = ((year >> 4) * 10) + (year & 0xF);
|
||||
int imonth = ((month >> 4) * 10) + (month & 0xF);
|
||||
int iday = ((day >> 4) * 10) + (day & 0xF);
|
||||
int iminute = ((minute >> 4) * 10) + (minute & 0xF);
|
||||
int ihour = ((hour >> 4) * 10) + (hour & 0xF);
|
||||
int isecond = ((second >> 4) * 10) + (second & 0xF);
|
||||
|
||||
return _julianEpoch.AddMilliseconds(delta);
|
||||
}
|
||||
|
||||
/// <summary>Converts an Amiga timestamp to a .NET DateTime</summary>
|
||||
/// <param name="days">Days since the 1st Jan. 1978</param>
|
||||
/// <param name="minutes">Minutes since o'clock</param>
|
||||
/// <param name="ticks">Ticks</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime AmigaToDateTime(uint days, uint minutes, uint ticks)
|
||||
{
|
||||
DateTime temp = _amigaEpoch.AddDays(days);
|
||||
temp = temp.AddMinutes(minutes);
|
||||
|
||||
return temp.AddMilliseconds(ticks * 20);
|
||||
}
|
||||
|
||||
/// <summary>Converts an UCSD Pascal timestamp to a .NET DateTime</summary>
|
||||
/// <param name="dateRecord">UCSD Pascal timestamp</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime UcsdPascalToDateTime(short dateRecord)
|
||||
{
|
||||
int year = ((dateRecord & 0xFE00) >> 9) + 1900;
|
||||
int day = (dateRecord & 0x01F0) >> 4;
|
||||
int month = dateRecord & 0x000F;
|
||||
|
||||
AaruConsole.DebugWriteLine("UCSDPascalToDateTime handler",
|
||||
"dateRecord = 0x{0:X4}, year = {1}, month = {2}, day = {3}", dateRecord, year,
|
||||
month, day);
|
||||
|
||||
return new DateTime(year, month, day);
|
||||
}
|
||||
|
||||
/// <summary>Converts a DOS timestamp to a .NET DateTime</summary>
|
||||
/// <param name="date">Date</param>
|
||||
/// <param name="time">Time</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime DosToDateTime(ushort date, ushort time)
|
||||
{
|
||||
int year = ((date & 0xFE00) >> 9) + 1980;
|
||||
int month = (date & 0x1E0) >> 5;
|
||||
int day = date & 0x1F;
|
||||
int hour = (time & 0xF800) >> 11;
|
||||
int minute = (time & 0x7E0) >> 5;
|
||||
int second = (time & 0x1F) * 2;
|
||||
|
||||
AaruConsole.DebugWriteLine("DOSToDateTime handler", "date = 0x{0:X4}, year = {1}, month = {2}, day = {3}",
|
||||
date, year, month, day);
|
||||
|
||||
AaruConsole.DebugWriteLine("DOSToDateTime handler",
|
||||
"time = 0x{0:X4}, hour = {1}, minute = {2}, second = {3}", time, hour, minute,
|
||||
second);
|
||||
|
||||
DateTime dosDate;
|
||||
|
||||
try
|
||||
{
|
||||
dosDate = new DateTime(year, month, day, hour, minute, second);
|
||||
}
|
||||
catch(ArgumentOutOfRangeException)
|
||||
{
|
||||
dosDate = new DateTime(1980, 1, 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
return dosDate;
|
||||
}
|
||||
|
||||
/// <summary>Converts a CP/M timestamp to .NET DateTime</summary>
|
||||
/// <param name="timestamp">CP/M timestamp</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime CpmToDateTime(byte[] timestamp)
|
||||
{
|
||||
ushort days = BitConverter.ToUInt16(timestamp, 0);
|
||||
int hours = timestamp[2];
|
||||
int minutes = timestamp[3];
|
||||
|
||||
DateTime temp = _amigaEpoch.AddDays(days);
|
||||
temp = temp.AddHours(hours);
|
||||
temp = temp.AddMinutes(minutes);
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>Converts an ECMA timestamp to a .NET DateTime</summary>
|
||||
/// <param name="typeAndTimeZone">Timezone</param>
|
||||
/// <param name="year">Year</param>
|
||||
/// <param name="month">Month</param>
|
||||
/// <param name="day">Day</param>
|
||||
/// <param name="hour">Hour</param>
|
||||
/// <param name="minute">Minute</param>
|
||||
/// <param name="second">Second</param>
|
||||
/// <param name="centiseconds">Centiseconds</param>
|
||||
/// <param name="hundredsOfMicroseconds">Hundreds of microseconds</param>
|
||||
/// <param name="microseconds">Microseconds</param>
|
||||
/// <returns></returns>
|
||||
public static DateTime EcmaToDateTime(ushort typeAndTimeZone, short year, byte month, byte day, byte hour,
|
||||
byte minute, byte second, byte centiseconds, byte hundredsOfMicroseconds,
|
||||
byte microseconds)
|
||||
{
|
||||
byte specification = (byte)((typeAndTimeZone & 0xF000) >> 12);
|
||||
|
||||
long ticks = ((long)centiseconds * 100000) + ((long)hundredsOfMicroseconds * 1000) +
|
||||
((long)microseconds * 10);
|
||||
|
||||
if(specification == 0)
|
||||
return new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc).AddTicks(ticks);
|
||||
|
||||
ushort preOffset = (ushort)(typeAndTimeZone & 0xFFF);
|
||||
short offset;
|
||||
|
||||
if((preOffset & 0x800) == 0x800)
|
||||
offset = (short)(preOffset | 0xF000);
|
||||
if(iyear >= 70)
|
||||
iyear += 1900;
|
||||
else
|
||||
offset = (short)(preOffset & 0x7FF);
|
||||
iyear += 2000;
|
||||
|
||||
if(offset == -2047)
|
||||
return new DateTime(year, month, day, hour, minute, second, DateTimeKind.Unspecified).AddTicks(ticks);
|
||||
|
||||
if(offset < -1440 ||
|
||||
offset > 1440)
|
||||
offset = 0;
|
||||
|
||||
return new DateTimeOffset(year, month, day, hour, minute, second, new TimeSpan(0, offset, 0)).
|
||||
AddTicks(ticks).DateTime;
|
||||
return new DateTime(iyear, imonth, iday, ihour, iminute, isecond);
|
||||
}
|
||||
|
||||
/// <summary>Converts a Solaris high resolution timestamp to .NET DateTime</summary>
|
||||
/// <param name="hrTimeStamp">Solaris high resolution timestamp</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime UnixHrTimeToDateTime(ulong hrTimeStamp) =>
|
||||
_unixEpoch.AddTicks((long)(hrTimeStamp / 100));
|
||||
|
||||
/// <summary>Converts an OS-9 timestamp to .NET DateTime</summary>
|
||||
/// <param name="date">OS-9 timestamp</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime Os9ToDateTime(byte[] date)
|
||||
catch(ArgumentOutOfRangeException)
|
||||
{
|
||||
if(date == null ||
|
||||
(date.Length != 3 && date.Length != 5))
|
||||
return DateTime.MinValue;
|
||||
|
||||
DateTime os9Date;
|
||||
|
||||
try
|
||||
{
|
||||
os9Date = date.Length == 5 ? new DateTime(1900 + date[0], date[1], date[2], date[3], date[4], 0)
|
||||
: new DateTime(1900 + date[0], date[1], date[2], 0, 0, 0);
|
||||
}
|
||||
catch(ArgumentOutOfRangeException)
|
||||
{
|
||||
os9Date = new DateTime(1900, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
return os9Date;
|
||||
}
|
||||
|
||||
/// <summary>Converts a LIF timestamp to .NET DateTime</summary>
|
||||
/// <param name="date">LIF timestamp</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime LifToDateTime(byte[] date)
|
||||
{
|
||||
if(date == null ||
|
||||
date.Length != 6)
|
||||
return new DateTime(1970, 1, 1, 0, 0, 0);
|
||||
|
||||
return LifToDateTime(date[0], date[1], date[2], date[3], date[4], date[5]);
|
||||
}
|
||||
|
||||
/// <summary>Converts a LIF timestamp to .NET DateTime</summary>
|
||||
/// <param name="year">Yer</param>
|
||||
/// <param name="month">Month</param>
|
||||
/// <param name="day">Day</param>
|
||||
/// <param name="hour">Hour</param>
|
||||
/// <param name="minute">Minute</param>
|
||||
/// <param name="second">Second</param>
|
||||
/// <returns>.NET DateTime</returns>
|
||||
public static DateTime LifToDateTime(byte year, byte month, byte day, byte hour, byte minute, byte second)
|
||||
{
|
||||
try
|
||||
{
|
||||
int iyear = ((year >> 4) * 10) + (year & 0xF);
|
||||
int imonth = ((month >> 4) * 10) + (month & 0xF);
|
||||
int iday = ((day >> 4) * 10) + (day & 0xF);
|
||||
int iminute = ((minute >> 4) * 10) + (minute & 0xF);
|
||||
int ihour = ((hour >> 4) * 10) + (hour & 0xF);
|
||||
int isecond = ((second >> 4) * 10) + (second & 0xF);
|
||||
|
||||
if(iyear >= 70)
|
||||
iyear += 1900;
|
||||
else
|
||||
iyear += 2000;
|
||||
|
||||
return new DateTime(iyear, imonth, iday, ihour, iminute, isecond);
|
||||
}
|
||||
catch(ArgumentOutOfRangeException)
|
||||
{
|
||||
return new DateTime(1970, 1, 1, 0, 0, 0);
|
||||
}
|
||||
return new DateTime(1970, 1, 1, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
893
Marshal.cs
893
Marshal.cs
@@ -36,463 +36,462 @@ using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Aaru.Helpers
|
||||
namespace Aaru.Helpers;
|
||||
|
||||
/// <summary>Provides methods to marshal binary data into C# structs</summary>
|
||||
public static class Marshal
|
||||
{
|
||||
/// <summary>Provides methods to marshal binary data into C# structs</summary>
|
||||
public static class Marshal
|
||||
/// <summary>Returns the size of an unmanaged type in bytes.</summary>
|
||||
/// <typeparam name="T">The type whose size is to be returned.</typeparam>
|
||||
/// <returns>The size, in bytes, of the type that is specified by the <see cref="T" /> generic type parameter.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int SizeOf<T>() => System.Runtime.InteropServices.Marshal.SizeOf<T>();
|
||||
|
||||
/// <summary>Marshal little-endian binary data to a structure</summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T ByteArrayToStructureLittleEndian<T>(byte[] bytes) where T : struct
|
||||
{
|
||||
/// <summary>Returns the size of an unmanaged type in bytes.</summary>
|
||||
/// <typeparam name="T">The type whose size is to be returned.</typeparam>
|
||||
/// <returns>The size, in bytes, of the type that is specified by the <see cref="T" /> generic type parameter.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int SizeOf<T>() => System.Runtime.InteropServices.Marshal.SizeOf<T>();
|
||||
var ptr = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
|
||||
/// <summary>Marshal little-endian binary data to a structure</summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T ByteArrayToStructureLittleEndian<T>(byte[] bytes) where T : struct
|
||||
var str = (T)System.Runtime.InteropServices.Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(T));
|
||||
|
||||
ptr.Free();
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/// <summary>Marshal little-endian binary data to a structure</summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <param name="start">Start on the array where the structure begins</param>
|
||||
/// <param name="length">Length of the structure in bytes</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T ByteArrayToStructureLittleEndian<T>(byte[] bytes, int start, int length) where T : struct
|
||||
{
|
||||
Span<byte> span = bytes;
|
||||
|
||||
return ByteArrayToStructureLittleEndian<T>(span.Slice(start, length).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>Marshal big-endian binary data to a structure</summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T ByteArrayToStructureBigEndian<T>(byte[] bytes) where T : struct
|
||||
{
|
||||
var ptr = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
|
||||
object str = (T)System.Runtime.InteropServices.Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(T));
|
||||
|
||||
ptr.Free();
|
||||
|
||||
return (T)SwapStructureMembersEndian(str);
|
||||
}
|
||||
|
||||
/// <summary>Marshal big-endian binary data to a structure</summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <param name="start">Start on the array where the structure begins</param>
|
||||
/// <param name="length">Length of the structure in bytes</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T ByteArrayToStructureBigEndian<T>(byte[] bytes, int start, int length) where T : struct
|
||||
{
|
||||
Span<byte> span = bytes;
|
||||
|
||||
return ByteArrayToStructureBigEndian<T>(span.Slice(start, length).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>Marshal PDP-11 binary data to a structure</summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T ByteArrayToStructurePdpEndian<T>(byte[] bytes) where T : struct
|
||||
{
|
||||
{
|
||||
var ptr = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
|
||||
var str = (T)System.Runtime.InteropServices.Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(T));
|
||||
object str =
|
||||
(T)System.Runtime.InteropServices.Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(T));
|
||||
|
||||
ptr.Free();
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/// <summary>Marshal little-endian binary data to a structure</summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <param name="start">Start on the array where the structure begins</param>
|
||||
/// <param name="length">Length of the structure in bytes</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T ByteArrayToStructureLittleEndian<T>(byte[] bytes, int start, int length) where T : struct
|
||||
{
|
||||
Span<byte> span = bytes;
|
||||
|
||||
return ByteArrayToStructureLittleEndian<T>(span.Slice(start, length).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>Marshal big-endian binary data to a structure</summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T ByteArrayToStructureBigEndian<T>(byte[] bytes) where T : struct
|
||||
{
|
||||
var ptr = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
|
||||
object str = (T)System.Runtime.InteropServices.Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(T));
|
||||
|
||||
ptr.Free();
|
||||
|
||||
return (T)SwapStructureMembersEndian(str);
|
||||
}
|
||||
|
||||
/// <summary>Marshal big-endian binary data to a structure</summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <param name="start">Start on the array where the structure begins</param>
|
||||
/// <param name="length">Length of the structure in bytes</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T ByteArrayToStructureBigEndian<T>(byte[] bytes, int start, int length) where T : struct
|
||||
{
|
||||
Span<byte> span = bytes;
|
||||
|
||||
return ByteArrayToStructureBigEndian<T>(span.Slice(start, length).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>Marshal PDP-11 binary data to a structure</summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T ByteArrayToStructurePdpEndian<T>(byte[] bytes) where T : struct
|
||||
{
|
||||
{
|
||||
var ptr = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
|
||||
object str =
|
||||
(T)System.Runtime.InteropServices.Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(T));
|
||||
|
||||
ptr.Free();
|
||||
|
||||
return (T)SwapStructureMembersEndianPdp(str);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Marshal PDP-11 binary data to a structure</summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <param name="start">Start on the array where the structure begins</param>
|
||||
/// <param name="length">Length of the structure in bytes</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T ByteArrayToStructurePdpEndian<T>(byte[] bytes, int start, int length) where T : struct
|
||||
{
|
||||
Span<byte> span = bytes;
|
||||
|
||||
return ByteArrayToStructurePdpEndian<T>(span.Slice(start, length).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marshal little-endian binary data to a structure. If the structure type contains any non value type, this
|
||||
/// method will crash.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T SpanToStructureLittleEndian<T>(ReadOnlySpan<byte> bytes) where T : struct =>
|
||||
MemoryMarshal.Read<T>(bytes);
|
||||
|
||||
/// <summary>
|
||||
/// Marshal little-endian binary data to a structure. If the structure type contains any non value type, this
|
||||
/// method will crash.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte span containing the binary data</param>
|
||||
/// <param name="start">Start on the span where the structure begins</param>
|
||||
/// <param name="length">Length of the structure in bytes</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T SpanToStructureLittleEndian<T>(ReadOnlySpan<byte> bytes, int start, int length)
|
||||
where T : struct => MemoryMarshal.Read<T>(bytes.Slice(start, length));
|
||||
|
||||
/// <summary>
|
||||
/// Marshal big-endian binary data to a structure. If the structure type contains any non value type, this method
|
||||
/// will crash.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T SpanToStructureBigEndian<T>(ReadOnlySpan<byte> bytes) where T : struct
|
||||
{
|
||||
T str = SpanToStructureLittleEndian<T>(bytes);
|
||||
|
||||
return (T)SwapStructureMembersEndian(str);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marshal big-endian binary data to a structure. If the structure type contains any non value type, this method
|
||||
/// will crash.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte span containing the binary data</param>
|
||||
/// <param name="start">Start on the span where the structure begins</param>
|
||||
/// <param name="length">Length of the structure in bytes</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T SpanToStructureBigEndian<T>(ReadOnlySpan<byte> bytes, int start, int length) where T : struct
|
||||
{
|
||||
T str = SpanToStructureLittleEndian<T>(bytes.Slice(start, length));
|
||||
|
||||
return (T)SwapStructureMembersEndian(str);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marshal PDP-11 binary data to a structure. If the structure type contains any non value type, this method will
|
||||
/// crash.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T SpanToStructurePdpEndian<T>(ReadOnlySpan<byte> bytes) where T : struct
|
||||
{
|
||||
object str = SpanToStructureLittleEndian<T>(bytes);
|
||||
|
||||
return (T)SwapStructureMembersEndianPdp(str);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marshal PDP-11 binary data to a structure. If the structure type contains any non value type, this method will
|
||||
/// crash.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <param name="start">Start on the span where the structure begins</param>
|
||||
/// <param name="length">Length of the structure in bytes</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T SpanToStructurePdpEndian<T>(ReadOnlySpan<byte> bytes, int start, int length) where T : struct
|
||||
{
|
||||
object str = SpanToStructureLittleEndian<T>(bytes.Slice(start, length));
|
||||
|
||||
return (T)SwapStructureMembersEndianPdp(str);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marshal a structure depending on the decoration of <see cref="MarshallingPropertiesAttribute" />. If the
|
||||
/// decoration is not present it will marshal as a reference type containing little endian structure.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// The <see cref="MarshallingPropertiesAttribute" /> contains an unsupported
|
||||
/// endian
|
||||
/// </exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T MarshalStructure<T>(byte[] bytes) where T : struct
|
||||
{
|
||||
if(!(typeof(T).GetCustomAttribute(typeof(MarshallingPropertiesAttribute)) is MarshallingPropertiesAttribute
|
||||
properties))
|
||||
return ByteArrayToStructureLittleEndian<T>(bytes);
|
||||
|
||||
switch(properties.Endian)
|
||||
{
|
||||
case BitEndian.Little:
|
||||
return properties.HasReferences ? ByteArrayToStructureLittleEndian<T>(bytes)
|
||||
: SpanToStructureLittleEndian<T>(bytes);
|
||||
|
||||
case BitEndian.Big:
|
||||
return properties.HasReferences ? ByteArrayToStructureBigEndian<T>(bytes)
|
||||
: SpanToStructureBigEndian<T>(bytes);
|
||||
|
||||
case BitEndian.Pdp:
|
||||
return properties.HasReferences ? ByteArrayToStructurePdpEndian<T>(bytes)
|
||||
: SpanToStructurePdpEndian<T>(bytes);
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Swaps all members of a structure</summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining), SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public static object SwapStructureMembersEndian(object str)
|
||||
{
|
||||
Type t = str.GetType();
|
||||
FieldInfo[] fieldInfo = t.GetFields();
|
||||
|
||||
foreach(FieldInfo fi in fieldInfo)
|
||||
if(fi.FieldType == typeof(short) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(short)))
|
||||
{
|
||||
short x = (short)fi.GetValue(str);
|
||||
fi.SetValue(str, (short)((x << 8) | ((x >> 8) & 0xFF)));
|
||||
}
|
||||
else if(fi.FieldType == typeof(int) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(int)))
|
||||
{
|
||||
int x = (int)fi.GetValue(str);
|
||||
x = (int)(((x << 8) & 0xFF00FF00) | (((uint)x >> 8) & 0xFF00FF));
|
||||
fi.SetValue(str, (int)(((uint)x << 16) | (((uint)x >> 16) & 0xFFFF)));
|
||||
}
|
||||
else if(fi.FieldType == typeof(long) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(long)))
|
||||
{
|
||||
long x = (long)fi.GetValue(str);
|
||||
x = ((x & 0x00000000FFFFFFFF) << 32) | (long)(((ulong)x & 0xFFFFFFFF00000000) >> 32);
|
||||
x = ((x & 0x0000FFFF0000FFFF) << 16) | (long)(((ulong)x & 0xFFFF0000FFFF0000) >> 16);
|
||||
x = ((x & 0x00FF00FF00FF00FF) << 8) | (long)(((ulong)x & 0xFF00FF00FF00FF00) >> 8);
|
||||
|
||||
fi.SetValue(str, x);
|
||||
}
|
||||
else if(fi.FieldType == typeof(ushort) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(ushort)))
|
||||
{
|
||||
ushort x = (ushort)fi.GetValue(str);
|
||||
fi.SetValue(str, (ushort)((x << 8) | (x >> 8)));
|
||||
}
|
||||
else if(fi.FieldType == typeof(uint) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(uint)))
|
||||
{
|
||||
uint x = (uint)fi.GetValue(str);
|
||||
x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0xFF00FF);
|
||||
fi.SetValue(str, (x << 16) | (x >> 16));
|
||||
}
|
||||
else if(fi.FieldType == typeof(ulong) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(ulong)))
|
||||
{
|
||||
ulong x = (ulong)fi.GetValue(str);
|
||||
x = ((x & 0x00000000FFFFFFFF) << 32) | ((x & 0xFFFFFFFF00000000) >> 32);
|
||||
x = ((x & 0x0000FFFF0000FFFF) << 16) | ((x & 0xFFFF0000FFFF0000) >> 16);
|
||||
x = ((x & 0x00FF00FF00FF00FF) << 8) | ((x & 0xFF00FF00FF00FF00) >> 8);
|
||||
fi.SetValue(str, x);
|
||||
}
|
||||
else if(fi.FieldType == typeof(float))
|
||||
{
|
||||
float flt = (float)fi.GetValue(str);
|
||||
byte[] flt_b = BitConverter.GetBytes(flt);
|
||||
|
||||
fi.SetValue(str, BitConverter.ToSingle(new[]
|
||||
{
|
||||
flt_b[3], flt_b[2], flt_b[1], flt_b[0]
|
||||
}, 0));
|
||||
}
|
||||
else if(fi.FieldType == typeof(double))
|
||||
{
|
||||
double dbl = (double)fi.GetValue(str);
|
||||
byte[] dbl_b = BitConverter.GetBytes(dbl);
|
||||
|
||||
fi.SetValue(str, BitConverter.ToDouble(new[]
|
||||
{
|
||||
dbl_b[7], dbl_b[6], dbl_b[5], dbl_b[4], dbl_b[3], dbl_b[2], dbl_b[1], dbl_b[0]
|
||||
}, 0));
|
||||
}
|
||||
else if(fi.FieldType == typeof(byte) ||
|
||||
fi.FieldType == typeof(sbyte))
|
||||
{
|
||||
// Do nothing, can't byteswap them!
|
||||
}
|
||||
else if(fi.FieldType == typeof(Guid))
|
||||
{
|
||||
// TODO: Swap GUID
|
||||
}
|
||||
|
||||
// TODO: Swap arrays
|
||||
else if(fi.FieldType.IsValueType &&
|
||||
!fi.FieldType.IsEnum &&
|
||||
!fi.FieldType.IsArray)
|
||||
{
|
||||
object obj = fi.GetValue(str);
|
||||
object strc = SwapStructureMembersEndian(obj);
|
||||
fi.SetValue(str, strc);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/// <summary>Swaps all fields in an structure considering them to follow PDP endian conventions</summary>
|
||||
/// <param name="str">Source structure</param>
|
||||
/// <returns>Resulting structure</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static object SwapStructureMembersEndianPdp(object str)
|
||||
{
|
||||
Type t = str.GetType();
|
||||
FieldInfo[] fieldInfo = t.GetFields();
|
||||
|
||||
foreach(FieldInfo fi in fieldInfo)
|
||||
if(fi.FieldType == typeof(short) ||
|
||||
fi.FieldType == typeof(long) ||
|
||||
fi.FieldType == typeof(ushort) ||
|
||||
fi.FieldType == typeof(ulong) ||
|
||||
fi.FieldType == typeof(float) ||
|
||||
fi.FieldType == typeof(double) ||
|
||||
fi.FieldType == typeof(byte) ||
|
||||
fi.FieldType == typeof(sbyte) ||
|
||||
fi.FieldType == typeof(Guid))
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
else if(fi.FieldType == typeof(int) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(int)))
|
||||
{
|
||||
int x = (int)fi.GetValue(str);
|
||||
fi.SetValue(str, ((x & 0xffffu) << 16) | ((x & 0xffff0000u) >> 16));
|
||||
}
|
||||
else if(fi.FieldType == typeof(uint) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(uint)))
|
||||
{
|
||||
uint x = (uint)fi.GetValue(str);
|
||||
fi.SetValue(str, ((x & 0xffffu) << 16) | ((x & 0xffff0000u) >> 16));
|
||||
}
|
||||
|
||||
// TODO: Swap arrays
|
||||
else if(fi.FieldType.IsValueType &&
|
||||
!fi.FieldType.IsEnum &&
|
||||
!fi.FieldType.IsArray)
|
||||
{
|
||||
object obj = fi.GetValue(str);
|
||||
object strc = SwapStructureMembersEndianPdp(obj);
|
||||
fi.SetValue(str, strc);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/// <summary>Marshal a structure to little-endian binary data</summary>
|
||||
/// <param name="str">The structure you want to marshal to binary</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The byte array representing the given structure</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static byte[] StructureToByteArrayLittleEndian<T>(T str) where T : struct
|
||||
{
|
||||
byte[] buf = new byte[SizeOf<T>()];
|
||||
var ptr = GCHandle.Alloc(buf, GCHandleType.Pinned);
|
||||
System.Runtime.InteropServices.Marshal.StructureToPtr(str, ptr.AddrOfPinnedObject(), false);
|
||||
ptr.Free();
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/// <summary>Marshal a structure to little-endian binary data</summary>
|
||||
/// <param name="str">The structure you want to marshal to binary</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The byte array representing the given structure</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static byte[] StructureToByteArrayBigEndian<T>(T str) where T : struct =>
|
||||
StructureToByteArrayLittleEndian((T)SwapStructureMembersEndian(str));
|
||||
|
||||
/// <summary>Converts a hexadecimal string into a byte array</summary>
|
||||
/// <param name="hex">Hexadecimal string</param>
|
||||
/// <param name="outBuf">Resulting byte array</param>
|
||||
/// <returns>Number of output bytes processed</returns>
|
||||
public static int ConvertFromHexAscii(string hex, out byte[] outBuf)
|
||||
{
|
||||
outBuf = null;
|
||||
|
||||
if(hex is null ||
|
||||
hex == "")
|
||||
return -1;
|
||||
|
||||
int off = 0;
|
||||
|
||||
if(hex[0] == '0' &&
|
||||
(hex[1] == 'x' || hex[1] == 'X'))
|
||||
{
|
||||
off = 2;
|
||||
}
|
||||
|
||||
outBuf = new byte[(hex.Length - off) / 2];
|
||||
int count = 0;
|
||||
|
||||
for(int i = off; i < hex.Length; i += 2)
|
||||
{
|
||||
char c = hex[i];
|
||||
|
||||
if(c < '0' ||
|
||||
(c > '9' && c < 'A') ||
|
||||
(c > 'F' && c < 'a') ||
|
||||
c > 'f')
|
||||
break;
|
||||
|
||||
c -= c >= 'a' && c <= 'f'
|
||||
? '\u0057'
|
||||
: c >= 'A' && c <= 'F'
|
||||
? '\u0037'
|
||||
: '\u0030';
|
||||
|
||||
outBuf[(i - off) / 2] = (byte)(c << 4);
|
||||
|
||||
c = hex[i + 1];
|
||||
|
||||
if(c < '0' ||
|
||||
(c > '9' && c < 'A') ||
|
||||
(c > 'F' && c < 'a') ||
|
||||
c > 'f')
|
||||
break;
|
||||
|
||||
c -= c >= 'a' && c <= 'f'
|
||||
? '\u0057'
|
||||
: c >= 'A' && c <= 'F'
|
||||
? '\u0037'
|
||||
: '\u0030';
|
||||
|
||||
outBuf[(i - off) / 2] += (byte)c;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Marshal PDP-11 binary data to a structure</summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <param name="start">Start on the array where the structure begins</param>
|
||||
/// <param name="length">Length of the structure in bytes</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T ByteArrayToStructurePdpEndian<T>(byte[] bytes, int start, int length) where T : struct
|
||||
{
|
||||
Span<byte> span = bytes;
|
||||
|
||||
return ByteArrayToStructurePdpEndian<T>(span.Slice(start, length).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marshal little-endian binary data to a structure. If the structure type contains any non value type, this
|
||||
/// method will crash.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T SpanToStructureLittleEndian<T>(ReadOnlySpan<byte> bytes) where T : struct =>
|
||||
MemoryMarshal.Read<T>(bytes);
|
||||
|
||||
/// <summary>
|
||||
/// Marshal little-endian binary data to a structure. If the structure type contains any non value type, this
|
||||
/// method will crash.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte span containing the binary data</param>
|
||||
/// <param name="start">Start on the span where the structure begins</param>
|
||||
/// <param name="length">Length of the structure in bytes</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T SpanToStructureLittleEndian<T>(ReadOnlySpan<byte> bytes, int start, int length)
|
||||
where T : struct => MemoryMarshal.Read<T>(bytes.Slice(start, length));
|
||||
|
||||
/// <summary>
|
||||
/// Marshal big-endian binary data to a structure. If the structure type contains any non value type, this method
|
||||
/// will crash.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T SpanToStructureBigEndian<T>(ReadOnlySpan<byte> bytes) where T : struct
|
||||
{
|
||||
T str = SpanToStructureLittleEndian<T>(bytes);
|
||||
|
||||
return (T)SwapStructureMembersEndian(str);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marshal big-endian binary data to a structure. If the structure type contains any non value type, this method
|
||||
/// will crash.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte span containing the binary data</param>
|
||||
/// <param name="start">Start on the span where the structure begins</param>
|
||||
/// <param name="length">Length of the structure in bytes</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T SpanToStructureBigEndian<T>(ReadOnlySpan<byte> bytes, int start, int length) where T : struct
|
||||
{
|
||||
T str = SpanToStructureLittleEndian<T>(bytes.Slice(start, length));
|
||||
|
||||
return (T)SwapStructureMembersEndian(str);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marshal PDP-11 binary data to a structure. If the structure type contains any non value type, this method will
|
||||
/// crash.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T SpanToStructurePdpEndian<T>(ReadOnlySpan<byte> bytes) where T : struct
|
||||
{
|
||||
object str = SpanToStructureLittleEndian<T>(bytes);
|
||||
|
||||
return (T)SwapStructureMembersEndianPdp(str);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marshal PDP-11 binary data to a structure. If the structure type contains any non value type, this method will
|
||||
/// crash.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <param name="start">Start on the span where the structure begins</param>
|
||||
/// <param name="length">Length of the structure in bytes</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T SpanToStructurePdpEndian<T>(ReadOnlySpan<byte> bytes, int start, int length) where T : struct
|
||||
{
|
||||
object str = SpanToStructureLittleEndian<T>(bytes.Slice(start, length));
|
||||
|
||||
return (T)SwapStructureMembersEndianPdp(str);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marshal a structure depending on the decoration of <see cref="MarshallingPropertiesAttribute" />. If the
|
||||
/// decoration is not present it will marshal as a reference type containing little endian structure.
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array containing the binary data</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The binary data marshalled in a structure with the specified type</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// The <see cref="MarshallingPropertiesAttribute" /> contains an unsupported
|
||||
/// endian
|
||||
/// </exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T MarshalStructure<T>(byte[] bytes) where T : struct
|
||||
{
|
||||
if(!(typeof(T).GetCustomAttribute(typeof(MarshallingPropertiesAttribute)) is MarshallingPropertiesAttribute
|
||||
properties))
|
||||
return ByteArrayToStructureLittleEndian<T>(bytes);
|
||||
|
||||
switch(properties.Endian)
|
||||
{
|
||||
case BitEndian.Little:
|
||||
return properties.HasReferences ? ByteArrayToStructureLittleEndian<T>(bytes)
|
||||
: SpanToStructureLittleEndian<T>(bytes);
|
||||
|
||||
case BitEndian.Big:
|
||||
return properties.HasReferences ? ByteArrayToStructureBigEndian<T>(bytes)
|
||||
: SpanToStructureBigEndian<T>(bytes);
|
||||
|
||||
case BitEndian.Pdp:
|
||||
return properties.HasReferences ? ByteArrayToStructurePdpEndian<T>(bytes)
|
||||
: SpanToStructurePdpEndian<T>(bytes);
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Swaps all members of a structure</summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining), SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public static object SwapStructureMembersEndian(object str)
|
||||
{
|
||||
Type t = str.GetType();
|
||||
FieldInfo[] fieldInfo = t.GetFields();
|
||||
|
||||
foreach(FieldInfo fi in fieldInfo)
|
||||
if(fi.FieldType == typeof(short) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(short)))
|
||||
{
|
||||
short x = (short)fi.GetValue(str);
|
||||
fi.SetValue(str, (short)((x << 8) | ((x >> 8) & 0xFF)));
|
||||
}
|
||||
else if(fi.FieldType == typeof(int) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(int)))
|
||||
{
|
||||
int x = (int)fi.GetValue(str);
|
||||
x = (int)(((x << 8) & 0xFF00FF00) | (((uint)x >> 8) & 0xFF00FF));
|
||||
fi.SetValue(str, (int)(((uint)x << 16) | (((uint)x >> 16) & 0xFFFF)));
|
||||
}
|
||||
else if(fi.FieldType == typeof(long) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(long)))
|
||||
{
|
||||
long x = (long)fi.GetValue(str);
|
||||
x = ((x & 0x00000000FFFFFFFF) << 32) | (long)(((ulong)x & 0xFFFFFFFF00000000) >> 32);
|
||||
x = ((x & 0x0000FFFF0000FFFF) << 16) | (long)(((ulong)x & 0xFFFF0000FFFF0000) >> 16);
|
||||
x = ((x & 0x00FF00FF00FF00FF) << 8) | (long)(((ulong)x & 0xFF00FF00FF00FF00) >> 8);
|
||||
|
||||
fi.SetValue(str, x);
|
||||
}
|
||||
else if(fi.FieldType == typeof(ushort) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(ushort)))
|
||||
{
|
||||
ushort x = (ushort)fi.GetValue(str);
|
||||
fi.SetValue(str, (ushort)((x << 8) | (x >> 8)));
|
||||
}
|
||||
else if(fi.FieldType == typeof(uint) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(uint)))
|
||||
{
|
||||
uint x = (uint)fi.GetValue(str);
|
||||
x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0xFF00FF);
|
||||
fi.SetValue(str, (x << 16) | (x >> 16));
|
||||
}
|
||||
else if(fi.FieldType == typeof(ulong) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(ulong)))
|
||||
{
|
||||
ulong x = (ulong)fi.GetValue(str);
|
||||
x = ((x & 0x00000000FFFFFFFF) << 32) | ((x & 0xFFFFFFFF00000000) >> 32);
|
||||
x = ((x & 0x0000FFFF0000FFFF) << 16) | ((x & 0xFFFF0000FFFF0000) >> 16);
|
||||
x = ((x & 0x00FF00FF00FF00FF) << 8) | ((x & 0xFF00FF00FF00FF00) >> 8);
|
||||
fi.SetValue(str, x);
|
||||
}
|
||||
else if(fi.FieldType == typeof(float))
|
||||
{
|
||||
float flt = (float)fi.GetValue(str);
|
||||
byte[] flt_b = BitConverter.GetBytes(flt);
|
||||
|
||||
fi.SetValue(str, BitConverter.ToSingle(new[]
|
||||
{
|
||||
flt_b[3], flt_b[2], flt_b[1], flt_b[0]
|
||||
}, 0));
|
||||
}
|
||||
else if(fi.FieldType == typeof(double))
|
||||
{
|
||||
double dbl = (double)fi.GetValue(str);
|
||||
byte[] dbl_b = BitConverter.GetBytes(dbl);
|
||||
|
||||
fi.SetValue(str, BitConverter.ToDouble(new[]
|
||||
{
|
||||
dbl_b[7], dbl_b[6], dbl_b[5], dbl_b[4], dbl_b[3], dbl_b[2], dbl_b[1], dbl_b[0]
|
||||
}, 0));
|
||||
}
|
||||
else if(fi.FieldType == typeof(byte) ||
|
||||
fi.FieldType == typeof(sbyte))
|
||||
{
|
||||
// Do nothing, can't byteswap them!
|
||||
}
|
||||
else if(fi.FieldType == typeof(Guid))
|
||||
{
|
||||
// TODO: Swap GUID
|
||||
}
|
||||
|
||||
// TODO: Swap arrays
|
||||
else if(fi.FieldType.IsValueType &&
|
||||
!fi.FieldType.IsEnum &&
|
||||
!fi.FieldType.IsArray)
|
||||
{
|
||||
object obj = fi.GetValue(str);
|
||||
object strc = SwapStructureMembersEndian(obj);
|
||||
fi.SetValue(str, strc);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/// <summary>Swaps all fields in an structure considering them to follow PDP endian conventions</summary>
|
||||
/// <param name="str">Source structure</param>
|
||||
/// <returns>Resulting structure</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static object SwapStructureMembersEndianPdp(object str)
|
||||
{
|
||||
Type t = str.GetType();
|
||||
FieldInfo[] fieldInfo = t.GetFields();
|
||||
|
||||
foreach(FieldInfo fi in fieldInfo)
|
||||
if(fi.FieldType == typeof(short) ||
|
||||
fi.FieldType == typeof(long) ||
|
||||
fi.FieldType == typeof(ushort) ||
|
||||
fi.FieldType == typeof(ulong) ||
|
||||
fi.FieldType == typeof(float) ||
|
||||
fi.FieldType == typeof(double) ||
|
||||
fi.FieldType == typeof(byte) ||
|
||||
fi.FieldType == typeof(sbyte) ||
|
||||
fi.FieldType == typeof(Guid))
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
else if(fi.FieldType == typeof(int) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(int)))
|
||||
{
|
||||
int x = (int)fi.GetValue(str);
|
||||
fi.SetValue(str, ((x & 0xffffu) << 16) | ((x & 0xffff0000u) >> 16));
|
||||
}
|
||||
else if(fi.FieldType == typeof(uint) ||
|
||||
(fi.FieldType.IsEnum && fi.FieldType.GetEnumUnderlyingType() == typeof(uint)))
|
||||
{
|
||||
uint x = (uint)fi.GetValue(str);
|
||||
fi.SetValue(str, ((x & 0xffffu) << 16) | ((x & 0xffff0000u) >> 16));
|
||||
}
|
||||
|
||||
// TODO: Swap arrays
|
||||
else if(fi.FieldType.IsValueType &&
|
||||
!fi.FieldType.IsEnum &&
|
||||
!fi.FieldType.IsArray)
|
||||
{
|
||||
object obj = fi.GetValue(str);
|
||||
object strc = SwapStructureMembersEndianPdp(obj);
|
||||
fi.SetValue(str, strc);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/// <summary>Marshal a structure to little-endian binary data</summary>
|
||||
/// <param name="str">The structure you want to marshal to binary</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The byte array representing the given structure</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static byte[] StructureToByteArrayLittleEndian<T>(T str) where T : struct
|
||||
{
|
||||
byte[] buf = new byte[SizeOf<T>()];
|
||||
var ptr = GCHandle.Alloc(buf, GCHandleType.Pinned);
|
||||
System.Runtime.InteropServices.Marshal.StructureToPtr(str, ptr.AddrOfPinnedObject(), false);
|
||||
ptr.Free();
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/// <summary>Marshal a structure to little-endian binary data</summary>
|
||||
/// <param name="str">The structure you want to marshal to binary</param>
|
||||
/// <typeparam name="T">Type of the structure to marshal</typeparam>
|
||||
/// <returns>The byte array representing the given structure</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static byte[] StructureToByteArrayBigEndian<T>(T str) where T : struct =>
|
||||
StructureToByteArrayLittleEndian((T)SwapStructureMembersEndian(str));
|
||||
|
||||
/// <summary>Converts a hexadecimal string into a byte array</summary>
|
||||
/// <param name="hex">Hexadecimal string</param>
|
||||
/// <param name="outBuf">Resulting byte array</param>
|
||||
/// <returns>Number of output bytes processed</returns>
|
||||
public static int ConvertFromHexAscii(string hex, out byte[] outBuf)
|
||||
{
|
||||
outBuf = null;
|
||||
|
||||
if(hex is null ||
|
||||
hex == "")
|
||||
return -1;
|
||||
|
||||
int off = 0;
|
||||
|
||||
if(hex[0] == '0' &&
|
||||
(hex[1] == 'x' || hex[1] == 'X'))
|
||||
{
|
||||
off = 2;
|
||||
}
|
||||
|
||||
outBuf = new byte[(hex.Length - off) / 2];
|
||||
int count = 0;
|
||||
|
||||
for(int i = off; i < hex.Length; i += 2)
|
||||
{
|
||||
char c = hex[i];
|
||||
|
||||
if(c < '0' ||
|
||||
(c > '9' && c < 'A') ||
|
||||
(c > 'F' && c < 'a') ||
|
||||
c > 'f')
|
||||
break;
|
||||
|
||||
c -= c >= 'a' && c <= 'f'
|
||||
? '\u0057'
|
||||
: c >= 'A' && c <= 'F'
|
||||
? '\u0037'
|
||||
: '\u0030';
|
||||
|
||||
outBuf[(i - off) / 2] = (byte)(c << 4);
|
||||
|
||||
c = hex[i + 1];
|
||||
|
||||
if(c < '0' ||
|
||||
(c > '9' && c < 'A') ||
|
||||
(c > 'F' && c < 'a') ||
|
||||
c > 'f')
|
||||
break;
|
||||
|
||||
c -= c >= 'a' && c <= 'f'
|
||||
? '\u0057'
|
||||
: c >= 'A' && c <= 'F'
|
||||
? '\u0037'
|
||||
: '\u0030';
|
||||
|
||||
outBuf[(i - off) / 2] += (byte)c;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -38,25 +38,24 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace Aaru.Helpers
|
||||
namespace Aaru.Helpers;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Defines properties to help marshalling structs from binary data</summary>
|
||||
[AttributeUsage(AttributeTargets.Struct)]
|
||||
public sealed class MarshallingPropertiesAttribute : Attribute
|
||||
{
|
||||
/// <inheritdoc />
|
||||
/// <summary>Defines properties to help marshalling structs from binary data</summary>
|
||||
[AttributeUsage(AttributeTargets.Struct)]
|
||||
public sealed class MarshallingPropertiesAttribute : Attribute
|
||||
/// <param name="endian">Defines properties to help marshalling structs from binary data</param>
|
||||
public MarshallingPropertiesAttribute(BitEndian endian)
|
||||
{
|
||||
/// <inheritdoc />
|
||||
/// <summary>Defines properties to help marshalling structs from binary data</summary>
|
||||
/// <param name="endian">Defines properties to help marshalling structs from binary data</param>
|
||||
public MarshallingPropertiesAttribute(BitEndian endian)
|
||||
{
|
||||
Endian = endian;
|
||||
HasReferences = true;
|
||||
}
|
||||
|
||||
/// <summary>c</summary>
|
||||
public BitEndian Endian { get; }
|
||||
/// <summary>Tells if the structure, or any nested structure, has any non-value type (e.g. arrays, strings, etc).</summary>
|
||||
public bool HasReferences { get; set; }
|
||||
Endian = endian;
|
||||
HasReferences = true;
|
||||
}
|
||||
|
||||
/// <summary>c</summary>
|
||||
public BitEndian Endian { get; }
|
||||
/// <summary>Tells if the structure, or any nested structure, has any non-value type (e.g. arrays, strings, etc).</summary>
|
||||
public bool HasReferences { get; set; }
|
||||
}
|
||||
155
PrintHex.cs
155
PrintHex.cs
@@ -33,104 +33,103 @@
|
||||
using System.Text;
|
||||
using Aaru.Console;
|
||||
|
||||
namespace Aaru.Helpers
|
||||
namespace Aaru.Helpers;
|
||||
|
||||
/// <summary>Helper operations to get hexadecimal representations of byte arrays</summary>
|
||||
public static class PrintHex
|
||||
{
|
||||
/// <summary>Helper operations to get hexadecimal representations of byte arrays</summary>
|
||||
public static class PrintHex
|
||||
/// <summary>Prints a byte array as hexadecimal values to the console</summary>
|
||||
/// <param name="array">Array</param>
|
||||
/// <param name="width">Width of line</param>
|
||||
public static void PrintHexArray(byte[] array, int width = 16) =>
|
||||
AaruConsole.WriteLine(ByteArrayToHexArrayString(array, width));
|
||||
|
||||
/// <summary>Prints a byte array as hexadecimal values to a string</summary>
|
||||
/// <param name="array">Array</param>
|
||||
/// <param name="width">Width of line</param>
|
||||
/// <param name="color">Use ANSI escape colors for sections</param>
|
||||
/// <returns>String containing hexadecimal values</returns>
|
||||
public static string ByteArrayToHexArrayString(byte[] array, int width = 16, bool color = false)
|
||||
{
|
||||
/// <summary>Prints a byte array as hexadecimal values to the console</summary>
|
||||
/// <param name="array">Array</param>
|
||||
/// <param name="width">Width of line</param>
|
||||
public static void PrintHexArray(byte[] array, int width = 16) =>
|
||||
AaruConsole.WriteLine(ByteArrayToHexArrayString(array, width));
|
||||
if(array is null)
|
||||
return null;
|
||||
|
||||
/// <summary>Prints a byte array as hexadecimal values to a string</summary>
|
||||
/// <param name="array">Array</param>
|
||||
/// <param name="width">Width of line</param>
|
||||
/// <param name="color">Use ANSI escape colors for sections</param>
|
||||
/// <returns>String containing hexadecimal values</returns>
|
||||
public static string ByteArrayToHexArrayString(byte[] array, int width = 16, bool color = false)
|
||||
// TODO: Color list
|
||||
// TODO: Allow to change width
|
||||
string str = "Offset";
|
||||
int rows = array.Length / 16;
|
||||
int last = array.Length % 16;
|
||||
int offsetLength = $"{array.Length:X}".Length;
|
||||
var sb = new StringBuilder();
|
||||
|
||||
if(last > 0)
|
||||
rows++;
|
||||
|
||||
if(last == 0)
|
||||
last = 16;
|
||||
|
||||
if(offsetLength < str.Length)
|
||||
offsetLength = str.Length;
|
||||
|
||||
while(str.Length < offsetLength)
|
||||
str += ' ';
|
||||
|
||||
if(color)
|
||||
sb.Append("\u001b[36m");
|
||||
|
||||
sb.Append(str);
|
||||
sb.Append(" ");
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
if(array is null)
|
||||
return null;
|
||||
sb.AppendFormat(" {0:X2}", i);
|
||||
}
|
||||
|
||||
// TODO: Color list
|
||||
// TODO: Allow to change width
|
||||
string str = "Offset";
|
||||
int rows = array.Length / 16;
|
||||
int last = array.Length % 16;
|
||||
int offsetLength = $"{array.Length:X}".Length;
|
||||
var sb = new StringBuilder();
|
||||
if(color)
|
||||
sb.Append("\u001b[0m");
|
||||
|
||||
if(last > 0)
|
||||
rows++;
|
||||
sb.AppendLine();
|
||||
|
||||
if(last == 0)
|
||||
last = 16;
|
||||
int b = 0;
|
||||
|
||||
if(offsetLength < str.Length)
|
||||
offsetLength = str.Length;
|
||||
|
||||
while(str.Length < offsetLength)
|
||||
str += ' ';
|
||||
string format = $"{{0:X{offsetLength}}}";
|
||||
|
||||
for(int i = 0; i < rows; i++)
|
||||
{
|
||||
if(color)
|
||||
sb.Append("\u001b[36m");
|
||||
|
||||
sb.Append(str);
|
||||
sb.Append(" ");
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
sb.AppendFormat(" {0:X2}", i);
|
||||
}
|
||||
sb.AppendFormat(format, b);
|
||||
|
||||
if(color)
|
||||
sb.Append("\u001b[0m");
|
||||
|
||||
sb.AppendLine();
|
||||
sb.Append(" ");
|
||||
int lastBytes = i == rows - 1 ? last : 16;
|
||||
int lastSpaces = 16 - lastBytes;
|
||||
|
||||
int b = 0;
|
||||
|
||||
string format = $"{{0:X{offsetLength}}}";
|
||||
|
||||
for(int i = 0; i < rows; i++)
|
||||
for(int j = 0; j < lastBytes; j++)
|
||||
{
|
||||
if(color)
|
||||
sb.Append("\u001b[36m");
|
||||
|
||||
sb.AppendFormat(format, b);
|
||||
|
||||
if(color)
|
||||
sb.Append("\u001b[0m");
|
||||
|
||||
sb.Append(" ");
|
||||
int lastBytes = i == rows - 1 ? last : 16;
|
||||
int lastSpaces = 16 - lastBytes;
|
||||
|
||||
for(int j = 0; j < lastBytes; j++)
|
||||
{
|
||||
sb.AppendFormat(" {0:X2}", array[b]);
|
||||
b++;
|
||||
}
|
||||
|
||||
for(int j = 0; j < lastSpaces; j++)
|
||||
sb.Append(" ");
|
||||
|
||||
b -= lastBytes;
|
||||
sb.Append(" ");
|
||||
|
||||
for(int j = 0; j < lastBytes; j++)
|
||||
{
|
||||
int v = array[b];
|
||||
sb.Append((v > 31 && v < 127) || v > 159 ? (char)v : '.');
|
||||
b++;
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
sb.AppendFormat(" {0:X2}", array[b]);
|
||||
b++;
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
for(int j = 0; j < lastSpaces; j++)
|
||||
sb.Append(" ");
|
||||
|
||||
b -= lastBytes;
|
||||
sb.Append(" ");
|
||||
|
||||
for(int j = 0; j < lastBytes; j++)
|
||||
{
|
||||
int v = array[b];
|
||||
sb.Append((v > 31 && v < 127) || v > 159 ? (char)v : '.');
|
||||
b++;
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
@@ -33,153 +33,152 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Aaru.Helpers
|
||||
namespace Aaru.Helpers;
|
||||
|
||||
/// <summary>Helper operations to work with strings</summary>
|
||||
public static class StringHandlers
|
||||
{
|
||||
/// <summary>Helper operations to work with strings</summary>
|
||||
public static class StringHandlers
|
||||
/// <summary>Converts a null-terminated (aka C string) ASCII byte array to a C# string</summary>
|
||||
/// <returns>The corresponding C# string</returns>
|
||||
/// <param name="cString">A null-terminated (aka C string) ASCII byte array</param>
|
||||
public static string CToString(byte[] cString) => CToString(cString, Encoding.ASCII);
|
||||
|
||||
/// <summary>Converts a null-terminated (aka C string) byte array with the specified encoding to a C# string</summary>
|
||||
/// <returns>The corresponding C# string</returns>
|
||||
/// <param name="cString">A null-terminated (aka C string) byte array in the specified encoding</param>
|
||||
/// <param name="encoding">Encoding.</param>
|
||||
/// <param name="twoBytes">Set if encoding uses 16-bit characters.</param>
|
||||
/// <param name="start">Start decoding at this position</param>
|
||||
public static string CToString(byte[] cString, Encoding encoding, bool twoBytes = false, int start = 0)
|
||||
{
|
||||
/// <summary>Converts a null-terminated (aka C string) ASCII byte array to a C# string</summary>
|
||||
/// <returns>The corresponding C# string</returns>
|
||||
/// <param name="cString">A null-terminated (aka C string) ASCII byte array</param>
|
||||
public static string CToString(byte[] cString) => CToString(cString, Encoding.ASCII);
|
||||
if(cString == null)
|
||||
return null;
|
||||
|
||||
/// <summary>Converts a null-terminated (aka C string) byte array with the specified encoding to a C# string</summary>
|
||||
/// <returns>The corresponding C# string</returns>
|
||||
/// <param name="cString">A null-terminated (aka C string) byte array in the specified encoding</param>
|
||||
/// <param name="encoding">Encoding.</param>
|
||||
/// <param name="twoBytes">Set if encoding uses 16-bit characters.</param>
|
||||
/// <param name="start">Start decoding at this position</param>
|
||||
public static string CToString(byte[] cString, Encoding encoding, bool twoBytes = false, int start = 0)
|
||||
int len = 0;
|
||||
|
||||
for(int i = start; i < cString.Length; i++)
|
||||
{
|
||||
if(cString == null)
|
||||
return null;
|
||||
|
||||
int len = 0;
|
||||
|
||||
for(int i = start; i < cString.Length; i++)
|
||||
{
|
||||
if(cString[i] == 0)
|
||||
if(twoBytes)
|
||||
if(cString[i] == 0)
|
||||
if(twoBytes)
|
||||
{
|
||||
if(i + 1 < cString.Length &&
|
||||
cString[i + 1] == 0)
|
||||
{
|
||||
if(i + 1 < cString.Length &&
|
||||
cString[i + 1] == 0)
|
||||
{
|
||||
len++;
|
||||
len++;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
len++;
|
||||
}
|
||||
|
||||
if(twoBytes && len % 2 > 0)
|
||||
len--;
|
||||
|
||||
byte[] dest = new byte[len];
|
||||
Array.Copy(cString, start, dest, 0, len);
|
||||
|
||||
return len == 0 ? "" : encoding.GetString(dest);
|
||||
}
|
||||
|
||||
/// <summary>Converts a length-prefixed (aka Pascal string) ASCII byte array to a C# string</summary>
|
||||
/// <returns>The corresponding C# string</returns>
|
||||
/// <param name="pascalString">A length-prefixed (aka Pascal string) ASCII byte array</param>
|
||||
public static string PascalToString(byte[] pascalString) => PascalToString(pascalString, Encoding.ASCII);
|
||||
|
||||
/// <summary>Converts a length-prefixed (aka Pascal string) ASCII byte array to a C# string</summary>
|
||||
/// <returns>The corresponding C# string</returns>
|
||||
/// <param name="pascalString">A length-prefixed (aka Pascal string) ASCII byte array</param>
|
||||
/// <param name="encoding">Encoding.</param>
|
||||
/// <param name="start">Start decoding at this position</param>
|
||||
public static string PascalToString(byte[] pascalString, Encoding encoding, int start = 0)
|
||||
{
|
||||
if(pascalString == null)
|
||||
return null;
|
||||
|
||||
byte length = pascalString[start];
|
||||
int len = 0;
|
||||
|
||||
for(int i = start + 1; i < length + 1 && i < pascalString.Length; i++)
|
||||
{
|
||||
if(pascalString[i] == 0)
|
||||
break;
|
||||
|
||||
len++;
|
||||
}
|
||||
|
||||
byte[] dest = new byte[len];
|
||||
Array.Copy(pascalString, start + 1, dest, 0, len);
|
||||
|
||||
return len == 0 ? "" : encoding.GetString(dest);
|
||||
}
|
||||
|
||||
/// <summary>Converts a space (' ', 0x20, ASCII SPACE) padded ASCII byte array to a C# string</summary>
|
||||
/// <returns>The corresponding C# string</returns>
|
||||
/// <param name="spacePaddedString">A space (' ', 0x20, ASCII SPACE) padded ASCII byte array</param>
|
||||
public static string SpacePaddedToString(byte[] spacePaddedString) =>
|
||||
SpacePaddedToString(spacePaddedString, Encoding.ASCII);
|
||||
|
||||
/// <summary>Converts a space (' ', 0x20, ASCII SPACE) padded ASCII byte array to a C# string</summary>
|
||||
/// <returns>The corresponding C# string</returns>
|
||||
/// <param name="spacePaddedString">A space (' ', 0x20, ASCII SPACE) padded ASCII byte array</param>
|
||||
/// <param name="encoding">Encoding.</param>
|
||||
/// <param name="start">Start decoding at this position</param>
|
||||
public static string SpacePaddedToString(byte[] spacePaddedString, Encoding encoding, int start = 0)
|
||||
{
|
||||
if(spacePaddedString == null)
|
||||
return null;
|
||||
|
||||
int len = start;
|
||||
|
||||
for(int i = spacePaddedString.Length; i >= start; i--)
|
||||
{
|
||||
if(i == start)
|
||||
return "";
|
||||
|
||||
if(spacePaddedString[i - 1] == 0x20)
|
||||
continue;
|
||||
|
||||
len = i;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return len == 0 ? "" : encoding.GetString(spacePaddedString, start, len);
|
||||
}
|
||||
|
||||
/// <summary>Converts an OSTA compressed unicode byte array to a C# string</summary>
|
||||
/// <returns>The C# string.</returns>
|
||||
/// <param name="dstring">OSTA compressed unicode byte array.</param>
|
||||
public static string DecompressUnicode(byte[] dstring)
|
||||
{
|
||||
ushort unicode;
|
||||
byte compId = dstring[0];
|
||||
string temp = "";
|
||||
|
||||
if(compId != 8 &&
|
||||
compId != 16)
|
||||
return null;
|
||||
|
||||
for(int byteIndex = 1; byteIndex < dstring.Length;)
|
||||
{
|
||||
if(compId == 16)
|
||||
unicode = (ushort)(dstring[byteIndex++] << 8);
|
||||
}
|
||||
}
|
||||
else
|
||||
unicode = 0;
|
||||
|
||||
if(byteIndex < dstring.Length)
|
||||
unicode |= dstring[byteIndex++];
|
||||
|
||||
if(unicode == 0)
|
||||
break;
|
||||
|
||||
temp += Encoding.Unicode.GetString(BitConverter.GetBytes(unicode));
|
||||
}
|
||||
|
||||
return temp;
|
||||
len++;
|
||||
}
|
||||
|
||||
if(twoBytes && len % 2 > 0)
|
||||
len--;
|
||||
|
||||
byte[] dest = new byte[len];
|
||||
Array.Copy(cString, start, dest, 0, len);
|
||||
|
||||
return len == 0 ? "" : encoding.GetString(dest);
|
||||
}
|
||||
|
||||
/// <summary>Converts a length-prefixed (aka Pascal string) ASCII byte array to a C# string</summary>
|
||||
/// <returns>The corresponding C# string</returns>
|
||||
/// <param name="pascalString">A length-prefixed (aka Pascal string) ASCII byte array</param>
|
||||
public static string PascalToString(byte[] pascalString) => PascalToString(pascalString, Encoding.ASCII);
|
||||
|
||||
/// <summary>Converts a length-prefixed (aka Pascal string) ASCII byte array to a C# string</summary>
|
||||
/// <returns>The corresponding C# string</returns>
|
||||
/// <param name="pascalString">A length-prefixed (aka Pascal string) ASCII byte array</param>
|
||||
/// <param name="encoding">Encoding.</param>
|
||||
/// <param name="start">Start decoding at this position</param>
|
||||
public static string PascalToString(byte[] pascalString, Encoding encoding, int start = 0)
|
||||
{
|
||||
if(pascalString == null)
|
||||
return null;
|
||||
|
||||
byte length = pascalString[start];
|
||||
int len = 0;
|
||||
|
||||
for(int i = start + 1; i < length + 1 && i < pascalString.Length; i++)
|
||||
{
|
||||
if(pascalString[i] == 0)
|
||||
break;
|
||||
|
||||
len++;
|
||||
}
|
||||
|
||||
byte[] dest = new byte[len];
|
||||
Array.Copy(pascalString, start + 1, dest, 0, len);
|
||||
|
||||
return len == 0 ? "" : encoding.GetString(dest);
|
||||
}
|
||||
|
||||
/// <summary>Converts a space (' ', 0x20, ASCII SPACE) padded ASCII byte array to a C# string</summary>
|
||||
/// <returns>The corresponding C# string</returns>
|
||||
/// <param name="spacePaddedString">A space (' ', 0x20, ASCII SPACE) padded ASCII byte array</param>
|
||||
public static string SpacePaddedToString(byte[] spacePaddedString) =>
|
||||
SpacePaddedToString(spacePaddedString, Encoding.ASCII);
|
||||
|
||||
/// <summary>Converts a space (' ', 0x20, ASCII SPACE) padded ASCII byte array to a C# string</summary>
|
||||
/// <returns>The corresponding C# string</returns>
|
||||
/// <param name="spacePaddedString">A space (' ', 0x20, ASCII SPACE) padded ASCII byte array</param>
|
||||
/// <param name="encoding">Encoding.</param>
|
||||
/// <param name="start">Start decoding at this position</param>
|
||||
public static string SpacePaddedToString(byte[] spacePaddedString, Encoding encoding, int start = 0)
|
||||
{
|
||||
if(spacePaddedString == null)
|
||||
return null;
|
||||
|
||||
int len = start;
|
||||
|
||||
for(int i = spacePaddedString.Length; i >= start; i--)
|
||||
{
|
||||
if(i == start)
|
||||
return "";
|
||||
|
||||
if(spacePaddedString[i - 1] == 0x20)
|
||||
continue;
|
||||
|
||||
len = i;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return len == 0 ? "" : encoding.GetString(spacePaddedString, start, len);
|
||||
}
|
||||
|
||||
/// <summary>Converts an OSTA compressed unicode byte array to a C# string</summary>
|
||||
/// <returns>The C# string.</returns>
|
||||
/// <param name="dstring">OSTA compressed unicode byte array.</param>
|
||||
public static string DecompressUnicode(byte[] dstring)
|
||||
{
|
||||
ushort unicode;
|
||||
byte compId = dstring[0];
|
||||
string temp = "";
|
||||
|
||||
if(compId != 8 &&
|
||||
compId != 16)
|
||||
return null;
|
||||
|
||||
for(int byteIndex = 1; byteIndex < dstring.Length;)
|
||||
{
|
||||
if(compId == 16)
|
||||
unicode = (ushort)(dstring[byteIndex++] << 8);
|
||||
else
|
||||
unicode = 0;
|
||||
|
||||
if(byteIndex < dstring.Length)
|
||||
unicode |= dstring[byteIndex++];
|
||||
|
||||
if(unicode == 0)
|
||||
break;
|
||||
|
||||
temp += Encoding.Unicode.GetString(BitConverter.GetBytes(unicode));
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
133
Swapping.cs
133
Swapping.cs
@@ -32,81 +32,80 @@
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Aaru.Helpers
|
||||
namespace Aaru.Helpers;
|
||||
|
||||
/// <summary>Helper operations to work with swapping endians</summary>
|
||||
public static class Swapping
|
||||
{
|
||||
/// <summary>Helper operations to work with swapping endians</summary>
|
||||
public static class Swapping
|
||||
/// <summary>Gets the PDP endian equivalent of the given little endian unsigned integer</summary>
|
||||
/// <param name="x">Little endian unsigned integer</param>
|
||||
/// <returns>PDP unsigned integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint PDPFromLittleEndian(uint x) => ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16);
|
||||
|
||||
/// <summary>Gets the PDP endian equivalent of the given big endian unsigned integer</summary>
|
||||
/// <param name="x">Big endian unsigned integer</param>
|
||||
/// <returns>PDP unsigned integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint PDPFromBigEndian(uint x) => ((x & 0xff00ff) << 8) | ((x & 0xff00ff00) >> 8);
|
||||
|
||||
/// <summary>Swaps the endian of the specified unsigned short integer</summary>
|
||||
/// <param name="x">Unsigned short integer</param>
|
||||
/// <returns>Swapped unsigned short integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ushort Swap(ushort x) => (ushort)((x << 8) | (x >> 8));
|
||||
|
||||
/// <summary>Swaps the endian of the specified signed short integer</summary>
|
||||
/// <param name="x">Signed short integer</param>
|
||||
/// <returns>Swapped signed short integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static short Swap(short x) => (short)((x << 8) | ((x >> 8) & 0xFF));
|
||||
|
||||
/// <summary>Swaps the endian of the specified unsigned integer</summary>
|
||||
/// <param name="x">Unsigned integer</param>
|
||||
/// <returns>Swapped unsigned integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Swap(uint x)
|
||||
{
|
||||
/// <summary>Gets the PDP endian equivalent of the given little endian unsigned integer</summary>
|
||||
/// <param name="x">Little endian unsigned integer</param>
|
||||
/// <returns>PDP unsigned integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint PDPFromLittleEndian(uint x) => ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16);
|
||||
x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0xFF00FF);
|
||||
|
||||
/// <summary>Gets the PDP endian equivalent of the given big endian unsigned integer</summary>
|
||||
/// <param name="x">Big endian unsigned integer</param>
|
||||
/// <returns>PDP unsigned integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint PDPFromBigEndian(uint x) => ((x & 0xff00ff) << 8) | ((x & 0xff00ff00) >> 8);
|
||||
return (x << 16) | (x >> 16);
|
||||
}
|
||||
|
||||
/// <summary>Swaps the endian of the specified unsigned short integer</summary>
|
||||
/// <param name="x">Unsigned short integer</param>
|
||||
/// <returns>Swapped unsigned short integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ushort Swap(ushort x) => (ushort)((x << 8) | (x >> 8));
|
||||
/// <summary>Swaps the endian of the specified signed integer</summary>
|
||||
/// <param name="x">Signed integer</param>
|
||||
/// <returns>Swapped signed integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int Swap(int x)
|
||||
{
|
||||
x = (int)(((x << 8) & 0xFF00FF00) | (((uint)x >> 8) & 0xFF00FF));
|
||||
|
||||
/// <summary>Swaps the endian of the specified signed short integer</summary>
|
||||
/// <param name="x">Signed short integer</param>
|
||||
/// <returns>Swapped signed short integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static short Swap(short x) => (short)((x << 8) | ((x >> 8) & 0xFF));
|
||||
return (int)(((uint)x << 16) | (((uint)x >> 16) & 0xFFFF));
|
||||
}
|
||||
|
||||
/// <summary>Swaps the endian of the specified unsigned integer</summary>
|
||||
/// <param name="x">Unsigned integer</param>
|
||||
/// <returns>Swapped unsigned integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Swap(uint x)
|
||||
{
|
||||
x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0xFF00FF);
|
||||
/// <summary>Swaps the endian of the specified unsigned long integer</summary>
|
||||
/// <param name="x">Unsigned long integer</param>
|
||||
/// <returns>Swapped unsigned long integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Swap(ulong x)
|
||||
{
|
||||
x = ((x & 0x00000000FFFFFFFF) << 32) | ((x & 0xFFFFFFFF00000000) >> 32);
|
||||
x = ((x & 0x0000FFFF0000FFFF) << 16) | ((x & 0xFFFF0000FFFF0000) >> 16);
|
||||
x = ((x & 0x00FF00FF00FF00FF) << 8) | ((x & 0xFF00FF00FF00FF00) >> 8);
|
||||
|
||||
return (x << 16) | (x >> 16);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/// <summary>Swaps the endian of the specified signed integer</summary>
|
||||
/// <param name="x">Signed integer</param>
|
||||
/// <returns>Swapped signed integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int Swap(int x)
|
||||
{
|
||||
x = (int)(((x << 8) & 0xFF00FF00) | (((uint)x >> 8) & 0xFF00FF));
|
||||
/// <summary>Swaps the endian of the specified signed long integer</summary>
|
||||
/// <param name="x">Signed long integer</param>
|
||||
/// <returns>Swapped signed long integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long Swap(long x)
|
||||
{
|
||||
x = ((x & 0x00000000FFFFFFFF) << 32) | (long)(((ulong)x & 0xFFFFFFFF00000000) >> 32);
|
||||
x = ((x & 0x0000FFFF0000FFFF) << 16) | (long)(((ulong)x & 0xFFFF0000FFFF0000) >> 16);
|
||||
x = ((x & 0x00FF00FF00FF00FF) << 8) | (long)(((ulong)x & 0xFF00FF00FF00FF00) >> 8);
|
||||
|
||||
return (int)(((uint)x << 16) | (((uint)x >> 16) & 0xFFFF));
|
||||
}
|
||||
|
||||
/// <summary>Swaps the endian of the specified unsigned long integer</summary>
|
||||
/// <param name="x">Unsigned long integer</param>
|
||||
/// <returns>Swapped unsigned long integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Swap(ulong x)
|
||||
{
|
||||
x = ((x & 0x00000000FFFFFFFF) << 32) | ((x & 0xFFFFFFFF00000000) >> 32);
|
||||
x = ((x & 0x0000FFFF0000FFFF) << 16) | ((x & 0xFFFF0000FFFF0000) >> 16);
|
||||
x = ((x & 0x00FF00FF00FF00FF) << 8) | ((x & 0xFF00FF00FF00FF00) >> 8);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/// <summary>Swaps the endian of the specified signed long integer</summary>
|
||||
/// <param name="x">Signed long integer</param>
|
||||
/// <returns>Swapped signed long integer</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long Swap(long x)
|
||||
{
|
||||
x = ((x & 0x00000000FFFFFFFF) << 32) | (long)(((ulong)x & 0xFFFFFFFF00000000) >> 32);
|
||||
x = ((x & 0x0000FFFF0000FFFF) << 16) | (long)(((ulong)x & 0xFFFF0000FFFF0000) >> 16);
|
||||
x = ((x & 0x00FF00FF00FF00FF) << 8) | (long)(((ulong)x & 0xFF00FF00FF00FF00) >> 8);
|
||||
|
||||
return x;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user