forked from amkovkov/GranuSightSoftware2
124 lines
4.6 KiB
C#
124 lines
4.6 KiB
C#
using System.Text;
|
|
using System.IO.Compression;
|
|
|
|
namespace GSS2.Core.Utils;
|
|
|
|
// Формат файла MultiDimensionalArray:
|
|
// 4 байта [MDA_ fourcc]
|
|
// 4 байта [int32 array_rang]
|
|
// 4 байта * array_rang [int32 array_shape]
|
|
// data compressed with zlib
|
|
public static class MultiDimensionalArraySerializer
|
|
{
|
|
public const string FOURCC = "MDA\0";
|
|
|
|
public static void Serialize(Stream stream, Array array)
|
|
{
|
|
var shape = GetShape(array);
|
|
long totalLength = GetTotalLength(shape);
|
|
|
|
using (var writer = new BinaryWriter(stream, Encoding.ASCII, true))
|
|
{
|
|
writer.Write(Encoding.ASCII.GetBytes(FOURCC));
|
|
|
|
writer.Write(array.Rank);
|
|
|
|
foreach (var length in shape)
|
|
writer.Write(length);
|
|
}
|
|
|
|
using (var zip = new ZLibStream(stream, CompressionMode.Compress))
|
|
using (var writer = new BinaryWriter(zip))
|
|
for (long i = 0; i < totalLength; i++)
|
|
{
|
|
int[] indices = GetIndices(i, shape);
|
|
var value = array.GetValue(indices);
|
|
switch (value)
|
|
{
|
|
case bool v: writer.Write(v); break;
|
|
case byte v: writer.Write(v); break;
|
|
case sbyte v: writer.Write(v); break;
|
|
case short v: writer.Write(v); break;
|
|
case ushort v: writer.Write(v); break;
|
|
case int v: writer.Write(v); break;
|
|
case uint v: writer.Write(v); break;
|
|
case long v: writer.Write(v); break;
|
|
case ulong v: writer.Write(v); break;
|
|
case double v: writer.Write(v); break;
|
|
case float v: writer.Write(v); break;
|
|
default: throw new NotSupportedException();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static Array Deserialize<T>(Stream stream) where T : unmanaged
|
|
{
|
|
int rank;
|
|
int[] shape;
|
|
using (var reader = new BinaryReader(stream, Encoding.ASCII, true))
|
|
{
|
|
var fourcc = Encoding.ASCII.GetString(reader.ReadBytes(4));
|
|
if (fourcc != FOURCC)
|
|
throw new FormatException();
|
|
|
|
rank = reader.ReadInt32();
|
|
|
|
shape = Enumerable.Range(0, rank)
|
|
.Select(_ => reader.ReadInt32())
|
|
.ToArray();
|
|
}
|
|
|
|
long totalLength = GetTotalLength(shape);
|
|
|
|
var array = Array.CreateInstance(typeof(T), shape);
|
|
|
|
using (var zip = new ZLibStream(stream, CompressionMode.Decompress))
|
|
using (var reader = new BinaryReader(zip))
|
|
for (long i = 0; i < totalLength; i++)
|
|
{
|
|
int[] indices = GetIndices(i, shape);
|
|
switch (Type.GetTypeCode(typeof(T)))
|
|
{
|
|
case TypeCode.Boolean: array.SetValue(reader.ReadBoolean(), indices); break;
|
|
case TypeCode.Byte: array.SetValue(reader.ReadByte(), indices); break;
|
|
case TypeCode.SByte: array.SetValue(reader.ReadSByte(), indices); break;
|
|
case TypeCode.Int16: array.SetValue(reader.ReadInt16(), indices); break;
|
|
case TypeCode.UInt16: array.SetValue(reader.ReadUInt16(), indices); break;
|
|
case TypeCode.Int32: array.SetValue(reader.ReadInt32(), indices); break;
|
|
case TypeCode.UInt32: array.SetValue(reader.ReadUInt32(), indices); break;
|
|
case TypeCode.Int64: array.SetValue(reader.ReadInt64(), indices); break;
|
|
case TypeCode.UInt64: array.SetValue(reader.ReadUInt64(), indices); break;
|
|
case TypeCode.Double: array.SetValue(reader.ReadDouble(), indices); break;
|
|
case TypeCode.Single: array.SetValue(reader.ReadSingle(), indices); break;
|
|
default: throw new NotSupportedException();
|
|
}
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
private static int[] GetIndices(long linearIndex, int[] lengths)
|
|
{
|
|
var indices = new int[lengths.Length];
|
|
|
|
for (int dim = lengths.Length - 1; dim >= 0; dim--)
|
|
{
|
|
indices[dim] = (int)(linearIndex % lengths[dim]);
|
|
linearIndex /= lengths[dim];
|
|
}
|
|
|
|
return indices;
|
|
}
|
|
private static long GetTotalLength(params int[] shape)
|
|
{
|
|
long totalLength = shape.First();
|
|
foreach (var length in shape.Skip(1))
|
|
totalLength *= length;
|
|
return totalLength;
|
|
}
|
|
private static int[] GetShape(Array array) =>
|
|
Enumerable.Range(0, array.Rank)
|
|
.Select(array.GetLength)
|
|
.ToArray();
|
|
}
|