diff --git a/SrcMod/Shell/Valve/VdfConvert.cs b/SrcMod/Shell/Valve/VdfConvert.cs index 5c64cda..fa919dd 100644 --- a/SrcMod/Shell/Valve/VdfConvert.cs +++ b/SrcMod/Shell/Valve/VdfConvert.cs @@ -1,58 +1,79 @@ -namespace SrcMod.Shell.Valve; +using System.Security.Cryptography; -interface static class VdfConvert +namespace SrcMod.Shell.Valve; + +public 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" } + { "\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) + 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); + if (node is VdfSingleNode single) SerializeSingleNode(writer, single, name, options, indentLevel); + else if (node is VdfTreeNode tree) SerializeTreeNode(writer, tree, name, options, indentLevel); else throw new("Unknown node type."); } private static void SerializeSingleNode(StreamWriter writer, VdfSingleNode node, string name, - ref VdfOptions options, int indentLevel) + VdfOptions options, int indentLevel) { - string serializedName = SerializeString(name, ref options), - serializedValue = SerializeObject(node.value, ref options); - writer.WriteLine($"{new string(' ', indentLevel)}{serializedName} {serializedValue}"); + writer.Write(new string(' ', indentLevel)); + writer.Write(SerializeString(name, options)); + writer.Write(' '); + + string serializedValue = SerializeString(SerializeObject(node.value, options), options); + writer.WriteLine(serializedValue); } private static void SerializeTreeNode(StreamWriter writer, VdfTreeNode node, string name, - ref VdfOptions options, int indentLevel) + VdfOptions options, int indentLevel) { - string serializedName = SerializeString(name, ref options), - serializedValue = ""; // TODO: serialize each value with a higher indent + writer.Write(new string(' ', indentLevel)); + writer.WriteLine(SerializeString(name, options)); + writer.WriteLine(new string(' ', indentLevel) + '{'); - string indent = new(' ', indentLevel); - writer.WriteLine($"{indent}{serializedName}\n{indent}{{\n{serializedValue}\n{indent}}}"); + foreach (KeyValuePair subNode in node) + { + if (subNode.Value is VdfSingleNode singleSubNode && singleSubNode.value.GetType().IsArray) + { + Array array = (Array)singleSubNode.value; + Dictionary items = new(); + for (int i = 0; i < array.Length; i++) + { + object? item = array.GetValue(i); + if (item is VdfNode subNodeItem) items.Add(i.ToString(), subNodeItem); + else items.Add(i.ToString(), new VdfSingleNode(item)); + } + } + else SerializeNode(writer, subNode.Value, subNode.Key, options, indentLevel + options.indentSize); + } + + writer.WriteLine(new string(' ', indentLevel) + '}'); } - private static string SerializeObject(object obj, ref VdfOptions options) + private static string SerializeObject(object obj, VdfOptions options) { - // TODO: serialize an object - return ""; + return obj.ToString() ?? string.Empty; } - private static string SerializeString(string content, ref VdfOptions options) + private static string SerializeString(string content, VdfOptions options) { if (options.useEscapeCodes) foreach (KeyValuePair escapeCode in p_escapeCodes) content = content.Replace(escapeCode.Key, escapeCode.Value); + if (options.useQuotes) content = $"\"{content}\""; return content; } } diff --git a/SrcMod/Shell/Valve/VdfOptions.cs b/SrcMod/Shell/Valve/VdfOptions.cs index 1d4fafa..2287658 100644 --- a/SrcMod/Shell/Valve/VdfOptions.cs +++ b/SrcMod/Shell/Valve/VdfOptions.cs @@ -6,6 +6,7 @@ public record class VdfOptions public bool closeWhenFinished; public int indentSize; + public bool resetStreamPosition; public bool useEscapeCodes; public bool useQuotes; @@ -13,6 +14,7 @@ public record class VdfOptions { closeWhenFinished = true; indentSize = 4; + resetStreamPosition = false; useEscapeCodes = false; useQuotes = false; } diff --git a/SrcMod/Shell/Valve/VdfSerializer.cs b/SrcMod/Shell/Valve/VdfSerializer.cs index da46265..b0509b8 100644 --- a/SrcMod/Shell/Valve/VdfSerializer.cs +++ b/SrcMod/Shell/Valve/VdfSerializer.cs @@ -14,8 +14,10 @@ public class VdfSerializer 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); + StreamWriter writer = new(stream, leaveOpen: !p_options.closeWhenFinished); + VdfConvert.SerializeNode(writer, parentNode, parentNodeName, p_options, 0); writer.Close(); + + if (!p_options.closeWhenFinished && p_options.resetStreamPosition) stream.Seek(0, SeekOrigin.Begin); } } diff --git a/SrcMod/Shell/Valve/VdfTreeNode.cs b/SrcMod/Shell/Valve/VdfTreeNode.cs index e39e8cf..e8e944e 100644 --- a/SrcMod/Shell/Valve/VdfTreeNode.cs +++ b/SrcMod/Shell/Valve/VdfTreeNode.cs @@ -1,6 +1,6 @@ namespace SrcMod.Shell.Valve; -public class VdfTreeNode : VdfNode +public class VdfTreeNode : VdfNode, IEnumerable> { public int SubNodeCount => p_subNodes.Count; @@ -29,4 +29,7 @@ public class VdfTreeNode : VdfNode p_subNodes[p_subNodes.Keys.ElementAt(index)] = value; } } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator> GetEnumerator() => p_subNodes.GetEnumerator(); }