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(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(file, fbs); } return result; } public static T DeserializeFrom(Stream stream, string fbs) { var path = Path.GetTempFileName(); stream.ExportToFile(path); var ret = DeserializeFrom(path, fbs); File.Delete(path); return ret; } public static T DeserializeFrom(string file, string fbs) { GenerateJsonFromFile(file, fbs); var text = ReadDeleteJsonFromFolder(); var obj = JsonConvert.DeserializeObject(text); Debug.Assert(obj != null); Debug.WriteLine($"Deserialized {Path.GetFileName(file)}"); return obj; } public static byte[][] SerializeFrom(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 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 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 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"; } }