|  | @@ -0,0 +1,177 @@
 | 
	
		
			
				|  |  | +using System;
 | 
	
		
			
				|  |  | +using System.Collections.Generic;
 | 
	
		
			
				|  |  | +using System.IO;
 | 
	
		
			
				|  |  | +using System.Linq;
 | 
	
		
			
				|  |  | +using System.Text;
 | 
	
		
			
				|  |  | +using ArcToolkitCLI.Commands.Options;
 | 
	
		
			
				|  |  | +using ArcToolkitCLI.Util;
 | 
	
		
			
				|  |  | +using CommandLine;
 | 
	
		
			
				|  |  | +using YamlDotNet.Core;
 | 
	
		
			
				|  |  | +using YamlDotNet.Serialization;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +namespace ArcToolkitCLI.Commands.Converters
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    [Verb("menu", HelpText = "Convert MENU files into YAML and back")]
 | 
	
		
			
				|  |  | +    public class MenuConverter : IConverterCommand, IInputOptions, IOutputOptions
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        private const string MENU_TAG = "CM3D2_MENU";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public int Run()
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var files = Glob.EnumerateFiles(Input);
 | 
	
		
			
				|  |  | +            Directory.CreateDirectory(Output);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (!files.Any())
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                Console.WriteLine("No files specified. Run `convert help tex` for help.");
 | 
	
		
			
				|  |  | +                return 0;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            foreach (var file in files)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var result = 0;
 | 
	
		
			
				|  |  | +                switch (file.Extension.ToLowerInvariant())
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    case ".menu":
 | 
	
		
			
				|  |  | +                        if ((result = MenuToYaml(file.FullName)) != 0)
 | 
	
		
			
				|  |  | +                            return result;
 | 
	
		
			
				|  |  | +                        break;
 | 
	
		
			
				|  |  | +                    case ".yaml":
 | 
	
		
			
				|  |  | +                        if ((result = YamlToMenu(file.FullName)) != 0)
 | 
	
		
			
				|  |  | +                            return result;
 | 
	
		
			
				|  |  | +                        break;
 | 
	
		
			
				|  |  | +                    default:
 | 
	
		
			
				|  |  | +                        Console.WriteLine($"File {file.FullName} is neither .png nor .tex file. Skipping...");
 | 
	
		
			
				|  |  | +                        break;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return 0;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public IEnumerable<string> Input { get; set; }
 | 
	
		
			
				|  |  | +        public string Output { get; set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private int YamlToMenu(string file)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var deserializer = new DeserializerBuilder().Build();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            MenuFile data;
 | 
	
		
			
				|  |  | +            try
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                data = deserializer.Deserialize<MenuFile>(new StreamReader(file, Encoding.UTF8));
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            catch (YamlException e)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                Console.WriteLine($"Failed to read YAML file because {e.Message}: {e.InnerException?.Message}");
 | 
	
		
			
				|  |  | +                return 1;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            using var ms = new MemoryStream();
 | 
	
		
			
				|  |  | +            using var dataBw = new BinaryWriter(ms, Encoding.UTF8);
 | 
	
		
			
				|  |  | +            using var bw =
 | 
	
		
			
				|  |  | +                new BinaryWriter(File.Create(Path.Combine(Output, $"{Path.GetFileNameWithoutExtension(file)}.menu")),
 | 
	
		
			
				|  |  | +                                 Encoding.UTF8);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            foreach (var dataMenuEntry in data.MenuEntries)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                dataBw.Write((byte)(dataMenuEntry.Data.Count + 1));
 | 
	
		
			
				|  |  | +                dataBw.Write(dataMenuEntry.Key);
 | 
	
		
			
				|  |  | +                foreach (var s in dataMenuEntry.Data)
 | 
	
		
			
				|  |  | +                    dataBw.Write(s);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            dataBw.Write((byte)0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            bw.Write(MENU_TAG);
 | 
	
		
			
				|  |  | +            bw.Write(data.Version);
 | 
	
		
			
				|  |  | +            bw.Write(data.Path);
 | 
	
		
			
				|  |  | +            bw.Write(data.Name);
 | 
	
		
			
				|  |  | +            bw.Write(data.Part);
 | 
	
		
			
				|  |  | +            bw.Write(data.Description);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var menuData = ms.ToArray();
 | 
	
		
			
				|  |  | +            bw.Write(menuData.Length);
 | 
	
		
			
				|  |  | +            bw.Write(menuData);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return 0;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private int MenuToYaml(string file)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            using var br = new BinaryReader(File.OpenRead(file), Encoding.UTF8);
 | 
	
		
			
				|  |  | +            var tag = br.ReadString();
 | 
	
		
			
				|  |  | +            if (tag != MENU_TAG)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                Console.WriteLine("Provided file is not a valid menu file!");
 | 
	
		
			
				|  |  | +                return 1;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var menuFile = new MenuFile
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                Version = br.ReadInt32(),
 | 
	
		
			
				|  |  | +                Path = br.ReadString(),
 | 
	
		
			
				|  |  | +                Name = br.ReadString(),
 | 
	
		
			
				|  |  | +                Part = br.ReadString(),
 | 
	
		
			
				|  |  | +                Description = br.ReadString(),
 | 
	
		
			
				|  |  | +                MenuEntries = new List<MenuEntry>()
 | 
	
		
			
				|  |  | +            };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            br.ReadInt32();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            while (true)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var n1 = br.ReadByte();
 | 
	
		
			
				|  |  | +                var strList = new List<string>();
 | 
	
		
			
				|  |  | +                if (n1 == 0)
 | 
	
		
			
				|  |  | +                    break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                for (var i = 0; i < n1; i++)
 | 
	
		
			
				|  |  | +                    strList.Add(br.ReadString());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if (strList.Count == 0)
 | 
	
		
			
				|  |  | +                    continue;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if (strList[0] == "end")
 | 
	
		
			
				|  |  | +                    break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                menuFile.MenuEntries.Add(new MenuEntry { Key = strList[0], Data = strList.Skip(1).ToList() });
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var serializer = new SerializerBuilder().Build();
 | 
	
		
			
				|  |  | +            var yaml = serializer.Serialize(menuFile);
 | 
	
		
			
				|  |  | +            File.WriteAllText(Path.Combine(Output, $"{Path.GetFileNameWithoutExtension(file)}.yaml"), yaml);
 | 
	
		
			
				|  |  | +            return 0;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private class MenuEntry
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            [YamlMember(Alias = "key")]
 | 
	
		
			
				|  |  | +            public string Key { get; set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            [YamlMember(Alias = "data")]
 | 
	
		
			
				|  |  | +            public List<string> Data { get; set; }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private class MenuFile
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            [YamlMember(Alias = "version")]
 | 
	
		
			
				|  |  | +            public int Version { get; set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            [YamlMember(Alias = "path")]
 | 
	
		
			
				|  |  | +            public string Path { get; set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            [YamlMember(Alias = "name")]
 | 
	
		
			
				|  |  | +            public string Name { get; set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            [YamlMember(Alias = "part")]
 | 
	
		
			
				|  |  | +            public string Part { get; set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            [YamlMember(Alias = "descriptions")]
 | 
	
		
			
				|  |  | +            public string Description { get; set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            [YamlMember(Alias = "menu_entries")]
 | 
	
		
			
				|  |  | +            public List<MenuEntry> MenuEntries { get; set; }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 |