Switch-Toolbox/Switch_Toolbox_Library/IO/FlatBuffer/FlatBufferConverter.cs

223 lines
7.6 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Windows.Forms;
using Newtonsoft.Json;
namespace Toolbox.Library.IO
{
//Ported from https://github.com/kwsch/pkNX/blob/58b0597feaf53b35f5c4424e5ec357f82d99c9fa/pkNX.WinForms/Dumping/FlatBufferConverter.cs
//While i could use flat buffer c# generated code, it's a giant mess code wise
public static class FlatBufferConverter
{
static FlatBufferConverter()
{
if (!Directory.Exists(FlatPath))
return;
var files = Directory.GetFiles(FlatPath);
foreach (var f in files)
File.Delete(f);
}
public static string DeserializeToJson(Stream stream, string fbs)
{
var path = Path.GetTempFileName();
stream.ExportToFile(path);
return DeserializeToJson(path, fbs);
}
public static string DeserializeToJson(string path, string fbs)
{
GenerateJsonFromFile(path, fbs);
var text = ReadDeleteJsonFromFolder();
File.Delete(path);
return text;
}
public static T[] DeserializeFrom<T>(string[] files, string fbs)
{
var result = new T[files.Length];
for (int i = 0; i < result.Length; i++)
{
var file = files[i];
result[i] = DeserializeFrom<T>(file, fbs);
}
return result;
}
public static T DeserializeFrom<T>(Stream stream, string fbs)
{
var path = Path.GetTempFileName();
stream.ExportToFile(path);
var ret = DeserializeFrom<T>(path, fbs);
File.Delete(path);
return ret;
}
public static T DeserializeFrom<T>(string file, string fbs)
{
GenerateJsonFromFile(file, fbs);
var text = ReadDeleteJsonFromFolder();
var obj = JsonConvert.DeserializeObject<T>(text);
Debug.Assert(obj != null);
Debug.WriteLine($"Deserialized {Path.GetFileName(file)}");
return obj;
}
public static byte[][] SerializeFrom<T>(T[] obj, string fbs)
{
var result = new byte[obj.Length][];
for (int i = 0; i < result.Length; i++)
{
var file = obj[i];
result[i] = SerializeFrom(file, fbs);
}
return result;
}
public static byte[] SerializeFrom<T>(T obj, string fbs)
{
string log = GenerateBinFrom(obj, fbs);
var fileName = fbs + ".bin";
var data = ReadDelete(fileName);
Debug.Assert(data.Length != 0);
Debug.WriteLine($"Serialized to {fileName}");
return data;
}
private static string ReadDeleteJsonFromFolder()
{
var jsonPath = Directory.GetFiles(FlatPath, "*.json")[0];
var text = File.ReadAllText(jsonPath);
File.Delete(jsonPath);
return text;
}
private static byte[] ReadDelete(string fileName)
{
var filePath = Path.Combine(FlatPath, fileName);
if (!System.IO.File.Exists(filePath))
throw new Exception($"Failed to save binary. {log}");
var data = File.ReadAllBytes(filePath);
File.Delete(filePath);
return data;
}
private static void GenerateJsonFromFile(string file, string fbs)
{
var fbsName = fbs + ".fbs";
var fbsPath = Path.Combine(FlatPath, fbsName);
Directory.CreateDirectory(FlatPath);
if (!File.Exists(fbsPath))
File.WriteAllBytes(fbsPath, GetSchema(fbs));
var fileName = Path.GetFileName(file);
var filePath = Path.Combine(FlatPath, fileName);
File.Copy(file, filePath, true);
var args = GetArgumentsDeserialize(fileName, fbsName);
RunFlatC(args);
File.Delete(filePath);
}
private static string GenerateBinFrom<T>(T obj, string fbs)
{
if (!Directory.Exists(FlatPath))
Directory.CreateDirectory(FlatPath);
var fbsName = fbs + ".fbs";
var jsonName = fbs + ".json";
var text = WriteJson(obj);
var fbsPath = Path.Combine(FlatPath, fbsName);
File.WriteAllBytes(fbsPath, GetSchema(fbs));
var jsonPath = Path.Combine(FlatPath, jsonName);
File.WriteAllText(jsonPath, text);
var args = GetArgumentsSerialize(jsonName, fbsName);
return RunFlatC(args);
}
public static string WriteJson<T>(T obj)
{
var serializer = new JsonSerializer();
using (var stringWriter = new StringWriter())
{
using (var writer = new JsonTextWriter(stringWriter)
{
QuoteName = false,
Formatting = Formatting.Indented,
IndentChar = ' ',
Indentation = 2
})
serializer.Serialize(writer, obj);
return stringWriter.ToString();
}
}
private static string log = "";
private static string RunFlatC(string args)
{
var fcp = Path.Combine(FlatPath, "flatc.exe");
if (!File.Exists(fcp))
File.WriteAllBytes(fcp, Properties.Resources.flatc);
var process = new Process
{
StartInfo = new ProcessStartInfo
{
WorkingDirectory = FlatPath,
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
FileName = "cmd.exe",
Arguments = $"/C flatc {args} & exit",
}
};
process.EnableRaisingEvents = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_OutputDataReceived);
process.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_ErrorDataReceived);
process.StartInfo.UseShellExecute = false;
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
return log;
}
private static void process_ErrorDataReceived(object sender, DataReceivedEventArgs e) {
if (e.Data != null) log = e.Data;
}
private static void process_OutputDataReceived(object sender, DataReceivedEventArgs e) {
if (e.Data != null) log = e.Data;
}
public static byte[] GetSchema(string name)
{
var obj = Properties.Resources.ResourceManager.GetObject(name);
if (!(obj is byte[])) {
throw new FileNotFoundException(nameof(name)); }
return (byte[])obj;
}
public static readonly string WorkingDirectory = Application.StartupPath;
public static readonly string FlatPath = Path.Combine(WorkingDirectory, "flatbuffers");
private static string GetArgumentsDeserialize(string file, string fbs) =>
$"-t {fbs} -- {file} --defaults-json --raw-binary";
private static string GetArgumentsSerialize(string file, string fbs) =>
$"-b {fbs} {file} --defaults-json";
}
}