Hopefully VDF deserialization works now.
This commit is contained in:
parent
1ee60cdf65
commit
7428ac9110
@ -17,11 +17,161 @@ public static class VdfConvert
|
||||
{ "\v", @"\v" }
|
||||
};
|
||||
|
||||
#region DeserializeNode
|
||||
public static VdfNode? DeserializeNode(StreamReader reader, VdfOptions options) =>
|
||||
DeserializeNode(reader, options, out _, null);
|
||||
|
||||
private static VdfNode? DeserializeNode(StreamReader reader, VdfOptions options, out string name,
|
||||
string? first)
|
||||
{
|
||||
string? header = first ?? (reader.ReadLine()?.Trim());
|
||||
if (header is null || string.IsNullOrEmpty(header))
|
||||
{
|
||||
name = string.Empty;
|
||||
return null;
|
||||
}
|
||||
|
||||
string[] parts = SplitContent(header, options);
|
||||
if (parts.Length > 2) throw new VdfSerializationException("Too many values in node.");
|
||||
|
||||
VdfNode node;
|
||||
|
||||
name = DeserializeString(parts[0], options);
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
object value = DeserializeObject(DeserializeString(parts[1], options));
|
||||
node = new VdfSingleNode(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
string? next = reader.ReadLine()?.Trim();
|
||||
if (next is null) throw new VdfSerializationException("Expected starting '{', found end-of-file.");
|
||||
else if (next != "{") throw new VdfSerializationException($"Expected starting '{{', found \"{next}\".");
|
||||
VdfTreeNode tree = new();
|
||||
string? current;
|
||||
while ((current = reader.ReadLine()?.Trim()) is not null)
|
||||
{
|
||||
if (current == "}") break;
|
||||
VdfNode? output = DeserializeNode(reader, options, out string subName, current);
|
||||
if (output is null) throw new VdfSerializationException("Error deserializing sub-node.");
|
||||
tree[subName] = output;
|
||||
}
|
||||
if (current is null) throw new VdfSerializationException("Reached end-of-file while deserializing group.");
|
||||
node = tree;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private static object DeserializeObject(string content) =>
|
||||
TypeParsers.ParseAll(content);
|
||||
private static string DeserializeString(string content, VdfOptions options)
|
||||
{
|
||||
if (options.useQuotes)
|
||||
{
|
||||
if (!content.StartsWith('\"') || !content.EndsWith('\"'))
|
||||
throw new VdfSerializationException("No quotes found around content.");
|
||||
content = content[1..^1];
|
||||
}
|
||||
if (options.useEscapeCodes)
|
||||
{
|
||||
foreach (KeyValuePair<string, string> escapeCode in p_escapeCodes.Reverse())
|
||||
content = content.Replace(escapeCode.Value, escapeCode.Key);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
private static string[] SplitContent(string content, VdfOptions options)
|
||||
{
|
||||
content = content.Replace('\t', ' ');
|
||||
if (options.useQuotes)
|
||||
{
|
||||
List<string> values = new();
|
||||
string current = string.Empty;
|
||||
bool inQuote = false;
|
||||
for (int i = 0; i < content.Length; i++)
|
||||
{
|
||||
char c = content[i];
|
||||
if (c == '\"' && !(i > 0 && content[i - 1] == '\\')) inQuote = !inQuote;
|
||||
|
||||
if (c == ' ' && !inQuote)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(current)) values.Add(current);
|
||||
current = string.Empty;
|
||||
}
|
||||
else current += c;
|
||||
}
|
||||
if (inQuote) throw new VdfSerializationException("Reached end-of-line while inside quotations.");
|
||||
if (!string.IsNullOrEmpty(current)) values.Add(current);
|
||||
return values.ToArray();
|
||||
}
|
||||
else return content.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SerializeNode
|
||||
public static void SerializeNode(StreamWriter writer, VdfNode? node, string name,
|
||||
VdfOptions options) => SerializeNode(writer, node, name, options, 0);
|
||||
public static void SerializeNode(StreamWriter writer, VdfNode? node, string name) =>
|
||||
SerializeNode(writer, node, name, VdfOptions.Default, 0);
|
||||
|
||||
private static void SerializeNode(StreamWriter writer, VdfNode? node, string name,
|
||||
VdfOptions options, int indentLevel)
|
||||
{
|
||||
if (node is null) return;
|
||||
else 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,
|
||||
VdfOptions options, int indentLevel)
|
||||
{
|
||||
string? serializedValue = SerializeObject(node.value);
|
||||
if (serializedValue is null) return;
|
||||
|
||||
writer.Write(new string(' ', indentLevel));
|
||||
writer.Write(SerializeString(name, options));
|
||||
writer.Write(' ');
|
||||
|
||||
serializedValue = SerializeString(serializedValue, options);
|
||||
writer.WriteLine(serializedValue);
|
||||
}
|
||||
private static void SerializeTreeNode(StreamWriter writer, VdfTreeNode node, string name,
|
||||
VdfOptions options, int indentLevel)
|
||||
{
|
||||
if (node.SubNodeCount <= 0) return;
|
||||
|
||||
writer.Write(new string(' ', indentLevel));
|
||||
writer.WriteLine(SerializeString(name, options));
|
||||
writer.WriteLine(new string(' ', indentLevel) + '{');
|
||||
|
||||
foreach (KeyValuePair<string, VdfNode?> subNode in node)
|
||||
SerializeNode(writer, subNode.Value, subNode.Key, options, indentLevel + options.indentSize);
|
||||
|
||||
writer.WriteLine(new string(' ', indentLevel) + '}');
|
||||
}
|
||||
|
||||
private static string? SerializeObject(object? obj)
|
||||
{
|
||||
if (obj is null) return null;
|
||||
return obj.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
private static string SerializeString(string content, VdfOptions options)
|
||||
{
|
||||
if (options.useEscapeCodes)
|
||||
{
|
||||
foreach (KeyValuePair<string, string> escapeCode in p_escapeCodes)
|
||||
content = content.Replace(escapeCode.Key, escapeCode.Value);
|
||||
}
|
||||
if (options.useQuotes) content = $"\"{content}\"";
|
||||
return content;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ToNodeTree
|
||||
public static VdfNode? ToNodeTree(object? obj) => ToNodeTree(obj, VdfOptions.Default);
|
||||
public static VdfNode? ToNodeTree(object? obj, VdfOptions options)
|
||||
{
|
||||
@ -43,7 +193,7 @@ public static class VdfConvert
|
||||
dictionary.Values.CopyTo(values, 0);
|
||||
for (int i = 0; i < dictionary.Count; i++)
|
||||
{
|
||||
tree[SerializeObject(keys.GetValue(i), options)!] = ToNodeTree(values.GetValue(i), options);
|
||||
tree[SerializeObject(keys.GetValue(i))!] = ToNodeTree(values.GetValue(i), options);
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
@ -52,7 +202,7 @@ public static class VdfConvert
|
||||
int index = 0;
|
||||
foreach (object item in enumerable)
|
||||
{
|
||||
tree[SerializeObject(index, options)!] = ToNodeTree(item, options);
|
||||
tree[SerializeObject(index)!] = ToNodeTree(item, options);
|
||||
index++;
|
||||
}
|
||||
return tree;
|
||||
@ -93,56 +243,5 @@ public static class VdfConvert
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
private static void SerializeNode(StreamWriter writer, VdfNode? node, string name,
|
||||
VdfOptions options, int indentLevel)
|
||||
{
|
||||
if (node is null) return;
|
||||
else 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,
|
||||
VdfOptions options, int indentLevel)
|
||||
{
|
||||
string? serializedValue = SerializeObject(node.value, options);
|
||||
if (serializedValue is null) return;
|
||||
|
||||
writer.Write(new string(' ', indentLevel));
|
||||
writer.Write(SerializeString(name, options));
|
||||
writer.Write(' ');
|
||||
|
||||
serializedValue = SerializeString(serializedValue, options);
|
||||
writer.WriteLine(serializedValue);
|
||||
}
|
||||
private static void SerializeTreeNode(StreamWriter writer, VdfTreeNode node, string name,
|
||||
VdfOptions options, int indentLevel)
|
||||
{
|
||||
if (node.SubNodeCount <= 0) return;
|
||||
|
||||
writer.Write(new string(' ', indentLevel));
|
||||
writer.WriteLine(SerializeString(name, options));
|
||||
writer.WriteLine(new string(' ', indentLevel) + '{');
|
||||
|
||||
foreach (KeyValuePair<string, VdfNode?> subNode in node)
|
||||
SerializeNode(writer, subNode.Value, subNode.Key, options, indentLevel + options.indentSize);
|
||||
|
||||
writer.WriteLine(new string(' ', indentLevel) + '}');
|
||||
}
|
||||
|
||||
private static string? SerializeObject(object? obj, VdfOptions options)
|
||||
{
|
||||
if (obj is null) return null;
|
||||
return obj.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
private static string SerializeString(string content, VdfOptions options)
|
||||
{
|
||||
if (options.useEscapeCodes)
|
||||
foreach (KeyValuePair<string, string> escapeCode in p_escapeCodes)
|
||||
content = content.Replace(escapeCode.Key, escapeCode.Value);
|
||||
if (options.useQuotes) content = $"\"{content}\"";
|
||||
return content;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
8
SrcMod/Shell/Valve/VdfSerializationException.cs
Normal file
8
SrcMod/Shell/Valve/VdfSerializationException.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace SrcMod.Shell.Valve;
|
||||
|
||||
public class VdfSerializationException : Exception
|
||||
{
|
||||
public VdfSerializationException() : base() { }
|
||||
public VdfSerializationException(string message) : base(message) { }
|
||||
public VdfSerializationException(string message, Exception inner) : base(message, inner) { }
|
||||
}
|
||||
@ -12,6 +12,17 @@ public class VdfSerializer
|
||||
p_options = options;
|
||||
}
|
||||
|
||||
public VdfNode? Deserialize(Stream stream)
|
||||
{
|
||||
long pos = stream.Position;
|
||||
StreamReader reader = new(stream, leaveOpen: !p_options.closeWhenFinished);
|
||||
VdfNode? result = VdfConvert.DeserializeNode(reader, p_options);
|
||||
reader.Close();
|
||||
|
||||
if (!p_options.closeWhenFinished && p_options.resetStreamPosition) stream.Seek(pos, SeekOrigin.Begin);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Serialize(Stream stream, object? value, string parentNodeName)
|
||||
{
|
||||
VdfNode? nodeTree = VdfConvert.ToNodeTree(value, p_options);
|
||||
@ -19,10 +30,11 @@ public class VdfSerializer
|
||||
}
|
||||
public void Serialize(Stream stream, VdfNode? parentNode, string parentNodeName)
|
||||
{
|
||||
long pos = stream.Position;
|
||||
StreamWriter writer = new(stream, leaveOpen: !p_options.closeWhenFinished);
|
||||
VdfConvert.SerializeNode(writer, parentNode, parentNodeName, p_options);
|
||||
writer.Close();
|
||||
|
||||
if (!p_options.closeWhenFinished && p_options.resetStreamPosition) stream.Seek(0, SeekOrigin.Begin);
|
||||
if (!p_options.closeWhenFinished && p_options.resetStreamPosition) stream.Seek(pos, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user