You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
6.0 KiB
162 lines
6.0 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.IO.Compression;
|
|
using System.Runtime.Serialization;
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
using Tools;
|
|
|
|
namespace napdump
|
|
{
|
|
[Flags]
|
|
public enum WritingOption : uint
|
|
{
|
|
/// <summary>
|
|
/// Serialize dump IBInfos
|
|
/// </summary>
|
|
Dump = 1 << 0,
|
|
/// <summary>
|
|
/// Serialize as binary IBInfos
|
|
/// </summary>
|
|
Binary = 1 << 1,
|
|
/// <summary>
|
|
/// Serialize as text IBInfos
|
|
/// </summary>
|
|
Text = 1<<2,
|
|
/// <summary>
|
|
/// (flag) GZ compress IBInfos
|
|
/// </summary>
|
|
Gz = 1 << 3,
|
|
/// <summary>
|
|
/// (flag) File system serialise format
|
|
/// </summary>
|
|
Fs = 1 << 4,
|
|
/// <summary>
|
|
/// Archive serialise format
|
|
/// </summary>
|
|
Ar = 1 << 5,
|
|
}
|
|
|
|
public static class BinWriter
|
|
{
|
|
public static WritingOption Options { get; private set; }
|
|
|
|
public static void Initialise(WritingOption opt)
|
|
{
|
|
Options = opt;
|
|
}
|
|
public static async Task SaveOptions(Stream to)
|
|
{
|
|
await to.WriteValueUnmanagedAsync<uint>((uint)Options);
|
|
}
|
|
public static async Task<WritingOption> LoadOptions(Stream from, CancellationToken token = default)
|
|
{
|
|
var opt = (WritingOption)await from.ReadValueUnmanagedAsync<uint>(token);
|
|
Initialise(opt);
|
|
return opt;
|
|
}
|
|
public static async Task WriteEntry<T>(Stream to, T toWrite, CancellationToken token=default) where T : ISerializable, IBinaryWritable, ITextWritable
|
|
{
|
|
var Options = BinWriter.Options;
|
|
if (Options.HasFlag(WritingOption.Gz))
|
|
to = new GZipStream(to, CompressionLevel.Optimal);
|
|
try
|
|
{
|
|
if (Options.HasFlag(WritingOption.Dump))
|
|
{
|
|
var binf = new BinaryFormatter();
|
|
await Task.Yield();
|
|
token.ThrowIfCancellationRequested();
|
|
binf.Serialize(to, toWrite);
|
|
}
|
|
else if (Options.HasFlag(WritingOption.Binary))
|
|
{
|
|
await to.WriteStringAsync(toWrite.GetType().AssemblyQualifiedName, token);
|
|
await toWrite.WriteBinaryAsync(to, token);
|
|
}
|
|
else if (Options.HasFlag(WritingOption.Text))
|
|
{
|
|
using (var textWriter = new StreamWriter(to))
|
|
{
|
|
await textWriter.WriteLineAsync($"Type={toWrite.GetType().AssemblyQualifiedName}".AsMemory(), token);
|
|
await textWriter.WriteLineAsync(new ReadOnlyMemory<char>(), token);
|
|
await toWrite.WriteTextAsync(textWriter, token);
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
if (Options.HasFlag(WritingOption.Gz))
|
|
await to.DisposeAsync();
|
|
}
|
|
}
|
|
|
|
public static async Task<object> ReadEntry(Stream from, CancellationToken token = default)
|
|
{
|
|
var Options = BinWriter.Options;
|
|
if (Options.HasFlag(WritingOption.Gz))
|
|
from = new GZipStream(from, CompressionMode.Decompress);
|
|
try
|
|
{
|
|
object value = default;
|
|
if (Options.HasFlag(WritingOption.Dump))
|
|
{
|
|
var binf = new BinaryFormatter();
|
|
await Task.Yield();
|
|
token.ThrowIfCancellationRequested();
|
|
value= binf.Deserialize(from);
|
|
}
|
|
else if (Options.HasFlag(WritingOption.Binary))
|
|
{
|
|
string typeName = await from.ReadStringAsync(token);
|
|
Type type = Type.GetType(typeName);
|
|
value = Activator.CreateInstance(type);
|
|
|
|
await ((value as IBinaryWritable)?.ReadBinaryAsync(from, token) ?? throw new InvalidDataException("Bad type definition: " + type.FullName + " does not implement IBinaryWritable"));
|
|
|
|
}
|
|
else if (Options.HasFlag(WritingOption.Text))
|
|
{
|
|
using (var reader = new StreamReader(from))
|
|
{
|
|
var line0 = await reader.ReadLineAsync();
|
|
token.ThrowIfCancellationRequested();
|
|
var def = line0.Split(new char[] { '=' }, 2);
|
|
await reader.ReadLineAsync();
|
|
|
|
token.ThrowIfCancellationRequested();
|
|
if (def.Length != 2||def[0].Trim().ToLower()!="type") throw new InvalidDataException("Bad type definition");
|
|
|
|
Type type = Type.GetType(def[1].Trim());
|
|
value = Activator.CreateInstance(type);
|
|
|
|
await ((value as ITextWritable)?.ReadTextAsync(reader, token) ?? throw new InvalidDataException("Bad type definition: "+type.FullName+" does not implement ITextWritable"));
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
finally
|
|
{
|
|
if (Options.HasFlag(WritingOption.Gz))
|
|
await from.DisposeAsync();
|
|
}
|
|
}
|
|
}
|
|
|
|
public interface IBinaryWritable
|
|
{
|
|
ValueTask WriteBinaryAsync(Stream to, CancellationToken cancel);
|
|
ValueTask ReadBinaryAsync(Stream from, CancellationToken cancel);
|
|
}
|
|
public interface ITextWritable
|
|
{
|
|
ValueTask WriteTextAsync(StreamWriter to, CancellationToken cancel);
|
|
ValueTask ReadTextAsync(StreamReader from, CancellationToken cancel);
|
|
}
|
|
}
|
|
|