diff --git a/SrcMod/Shell/GlobalUsings.cs b/SrcMod/Shell/GlobalUsings.cs index 19bbcbb..a30eee1 100644 --- a/SrcMod/Shell/GlobalUsings.cs +++ b/SrcMod/Shell/GlobalUsings.cs @@ -7,6 +7,7 @@ global using SrcMod.Shell.Extensions; global using SrcMod.Shell.Interop; global using SrcMod.Shell.Modules.ObjectModels; global using SrcMod.Shell.ObjectModels; +global using SrcMod.Shell.Valve; global using System; global using System.Collections; global using System.Collections.Generic; diff --git a/SrcMod/Shell/Valve/KeyValueConvert.cs b/SrcMod/Shell/Valve/KeyValueConvert.cs deleted file mode 100644 index a52b2fe..0000000 --- a/SrcMod/Shell/Valve/KeyValueConvert.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace SrcMod.Shell.Valve; - -public static class KeyValueConvert -{ - private static readonly Dictionary p_escapeCodes = new() - { - { "\'", "\\\'" }, - { "\"", "\\\"" }, - { "\\", "\\\\" }, - { "\0", "\\\0" }, - { "\a", "\\\a" }, - { "\b", "\\\b" }, - { "\f", "\\\f" }, - { "\n", "\\\n" }, - { "\r", "\\\r" }, - { "\t", "\\\t" }, - { "\v", "\\\v" } - }; - - public static string SerializeName(string content, KeyValueSerializer.Options? options = null) - { - options ??= KeyValueSerializer.Options.Default; - if (options.useNameQuotes) content = $"\"{content}\""; - if (options.useEscapeCodes) - foreach (KeyValuePair escapeCode in p_escapeCodes) - content = content.Replace(escapeCode.Key, escapeCode.Value); - - return content; - } -} diff --git a/SrcMod/Shell/Valve/KeyValueNode.cs b/SrcMod/Shell/Valve/KeyValueNode.cs deleted file mode 100644 index 5d88f77..0000000 --- a/SrcMod/Shell/Valve/KeyValueNode.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace SrcMod.Shell.Valve; - -public class KeyValueNode -{ - public int SubNodeCount => p_subNodes.Count; - - public object value; - - private Dictionary p_subNodes; - - internal KeyValueNode() - { - value = new(); - p_subNodes = new(); - } - - public KeyValueNode this[string name] => p_subNodes[name]; -} diff --git a/SrcMod/Shell/Valve/KeyValueSerializer.cs b/SrcMod/Shell/Valve/KeyValueSerializer.cs deleted file mode 100644 index 399ac4a..0000000 --- a/SrcMod/Shell/Valve/KeyValueSerializer.cs +++ /dev/null @@ -1,41 +0,0 @@ -namespace SrcMod.Shell.Valve; - -public class KeyValueSerializer -{ - public int? IndentSize => p_options.indentSize; - public bool UseEscapeCodes => p_options.useEscapeCodes; - public bool UseNameQuotes => p_options.useNameQuotes; - public bool UseValueQuotes => p_options.useValueQuotes; - - private readonly Options p_options; - - public KeyValueSerializer() : this(Options.Default) { } - public KeyValueSerializer(Options options) - { - p_options = options; - } - - public StringBuilder Serialize(StringBuilder builder, KeyValueNode parentNode, string? parentNodeName = null) - { - if (parentNodeName is not null) builder.AppendLine(KeyValueConvert.SerializeName(parentNodeName, p_options)); - return builder; - } - - public record class Options - { - public static Options Default => new(); - - public int? indentSize; - public bool useEscapeCodes; - public bool useNameQuotes; - public bool useValueQuotes; - - public Options() - { - indentSize = null; - useEscapeCodes = false; - useNameQuotes = true; - useValueQuotes = false; - } - } -} diff --git a/SrcMod/Shell/Valve/VdfConvert.cs b/SrcMod/Shell/Valve/VdfConvert.cs new file mode 100644 index 0000000..5c64cda --- /dev/null +++ b/SrcMod/Shell/Valve/VdfConvert.cs @@ -0,0 +1,58 @@ +namespace SrcMod.Shell.Valve; + +interface static class VdfConvert +{ + private static readonly Dictionary p_escapeCodes = new() + { + { "\'", "\\\'" }, + { "\"", "\\\"" }, + { "\\", "\\\\" }, + { "\0", "\\\0" }, + { "\a", "\\\a" }, + { "\b", "\\\b" }, + { "\f", "\\\f" }, + { "\n", "\\\n" }, + { "\r", "\\\r" }, + { "\t", "\\\t" }, + { "\v", "\\\v" } + }; + + public static void SerializeNode(StreamWriter writer, VdfNode node, string name, + ref VdfOptions options, int indentLevel) + { + if (node is VdfSingleNode single) SerializeSingleNode(writer, single, name, ref options, indentLevel); + else if (node is VdfTreeNode tree) SerializeTreeNode(writer, tree, name, ref options, indentLevel); + else throw new("Unknown node type."); + } + + private static void SerializeSingleNode(StreamWriter writer, VdfSingleNode node, string name, + ref VdfOptions options, int indentLevel) + { + string serializedName = SerializeString(name, ref options), + serializedValue = SerializeObject(node.value, ref options); + writer.WriteLine($"{new string(' ', indentLevel)}{serializedName} {serializedValue}"); + } + private static void SerializeTreeNode(StreamWriter writer, VdfTreeNode node, string name, + ref VdfOptions options, int indentLevel) + { + string serializedName = SerializeString(name, ref options), + serializedValue = ""; // TODO: serialize each value with a higher indent + + string indent = new(' ', indentLevel); + writer.WriteLine($"{indent}{serializedName}\n{indent}{{\n{serializedValue}\n{indent}}}"); + } + + private static string SerializeObject(object obj, ref VdfOptions options) + { + // TODO: serialize an object + return ""; + } + + private static string SerializeString(string content, ref VdfOptions options) + { + if (options.useEscapeCodes) + foreach (KeyValuePair escapeCode in p_escapeCodes) + content = content.Replace(escapeCode.Key, escapeCode.Value); + return content; + } +} diff --git a/SrcMod/Shell/Valve/VdfNode.cs b/SrcMod/Shell/Valve/VdfNode.cs new file mode 100644 index 0000000..36f3326 --- /dev/null +++ b/SrcMod/Shell/Valve/VdfNode.cs @@ -0,0 +1,6 @@ +namespace SrcMod.Shell.Valve; + +public abstract class VdfNode +{ + +} diff --git a/SrcMod/Shell/Valve/VdfOptions.cs b/SrcMod/Shell/Valve/VdfOptions.cs new file mode 100644 index 0000000..1d4fafa --- /dev/null +++ b/SrcMod/Shell/Valve/VdfOptions.cs @@ -0,0 +1,19 @@ +namespace SrcMod.Shell.Valve; + +public record class VdfOptions +{ + public static VdfOptions Default => new(); + + public bool closeWhenFinished; + public int indentSize; + public bool useEscapeCodes; + public bool useQuotes; + + public VdfOptions() + { + closeWhenFinished = true; + indentSize = 4; + useEscapeCodes = false; + useQuotes = false; + } +} diff --git a/SrcMod/Shell/Valve/VdfSerializer.cs b/SrcMod/Shell/Valve/VdfSerializer.cs new file mode 100644 index 0000000..da46265 --- /dev/null +++ b/SrcMod/Shell/Valve/VdfSerializer.cs @@ -0,0 +1,21 @@ +namespace SrcMod.Shell.Valve; + +public class VdfSerializer +{ + public VdfOptions Options => p_options; + + private VdfOptions p_options; + + public VdfSerializer() : this(VdfOptions.Default) { } + public VdfSerializer(VdfOptions options) + { + p_options = options; + } + + public void Serialize(Stream stream, VdfNode parentNode, string parentNodeName) + { + StreamWriter writer = p_options.closeWhenFinished ? new(stream) : new(stream, leaveOpen: true); + VdfConvert.SerializeNode(writer, parentNode, parentNodeName, ref p_options, 0); + writer.Close(); + } +} diff --git a/SrcMod/Shell/Valve/VdfSingleNode.cs b/SrcMod/Shell/Valve/VdfSingleNode.cs new file mode 100644 index 0000000..5e68b48 --- /dev/null +++ b/SrcMod/Shell/Valve/VdfSingleNode.cs @@ -0,0 +1,11 @@ +namespace SrcMod.Shell.Valve; + +public class VdfSingleNode : VdfNode +{ + public object value; + + public VdfSingleNode(object? value = null) : base() + { + this.value = value ?? new(); + } +} diff --git a/SrcMod/Shell/Valve/VdfTreeNode.cs b/SrcMod/Shell/Valve/VdfTreeNode.cs new file mode 100644 index 0000000..e39e8cf --- /dev/null +++ b/SrcMod/Shell/Valve/VdfTreeNode.cs @@ -0,0 +1,32 @@ +namespace SrcMod.Shell.Valve; + +public class VdfTreeNode : VdfNode +{ + public int SubNodeCount => p_subNodes.Count; + + private Dictionary p_subNodes; + + public VdfTreeNode(Dictionary? subNodes = null) : base() + { + p_subNodes = subNodes ?? new(); + } + + public VdfNode this[string key] + { + get => p_subNodes[key]; + set + { + if (p_subNodes.ContainsKey(key)) p_subNodes[key] = value; + else p_subNodes.Add(key, value); + } + } + public VdfNode this[int index] + { + get => p_subNodes.Values.ElementAt(index); + set + { + if (p_subNodes.Count >= index || index < 0) throw new IndexOutOfRangeException(); + p_subNodes[p_subNodes.Keys.ElementAt(index)] = value; + } + } +}