Added VDF Generator
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
namespace EonaCat.FirstLight.SaveTransfer.VdfGenerator.KeyValue.Interfaces;
|
||||
|
||||
public interface IKeyValueNode
|
||||
{
|
||||
string Key { get; }
|
||||
}
|
||||
55
007SaveTool/VdfGenerator/KeyValue/KeyValueDeserializer.cs
Normal file
55
007SaveTool/VdfGenerator/KeyValue/KeyValueDeserializer.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using EonaCat.FirstLight.SaveTransfer.VdfGenerator.KeyValue.Models;
|
||||
|
||||
namespace EonaCat.FirstLight.SaveTransfer.VdfGenerator.KeyValue;
|
||||
|
||||
/// <summary>
|
||||
/// Provides static methods for deserializing text representations of key-value groups into KvGroup objects.
|
||||
/// </summary>
|
||||
public static class KeyValueDeserializer
|
||||
{
|
||||
/// <summary>
|
||||
/// Deserializes the specified text into a KvGroup object.
|
||||
/// </summary>
|
||||
/// <param name="text">The input string containing the serialized representation of a KvGroup. Cannot be null.</param>
|
||||
/// <returns>A KvGroup object that represents the data contained in the input text.</returns>
|
||||
public static KeyValueGroup Deserialize(string text)
|
||||
{
|
||||
var tokenizer = new KeyValueTokenizer(text);
|
||||
return ParseGroup(tokenizer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a group from the provided tokenizer, including any nested groups or key-value pairs.
|
||||
/// </summary>
|
||||
/// <param name="t">The tokenizer used to read group names, symbols, and key-value pairs from the input stream. Must not be null and must be positioned at the start of a group.</param>
|
||||
/// <param name="k">The optional name of the group to parse. If null, the group name is read from the tokenizer.</param>
|
||||
/// <returns>A KvGroup representing the parsed group, including all nested groups and key-value pairs.</returns>
|
||||
private static KeyValueGroup ParseGroup(KeyValueTokenizer t, string? k = null)
|
||||
{
|
||||
// Expect group name
|
||||
var groupName = k ?? t.ReadString();
|
||||
var group = new KeyValueGroup(groupName);
|
||||
|
||||
t.ReadSymbol('{');
|
||||
|
||||
while (!t.PeekSymbol('}'))
|
||||
{
|
||||
var key = t.ReadString();
|
||||
|
||||
if (t.PeekSymbol('{'))
|
||||
{
|
||||
// Nested group
|
||||
group.Nodes.Add(ParseGroup(t, key));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Key-value pair
|
||||
var value = t.ReadString();
|
||||
group.Nodes.Add(new Models.KeyValuePair(key, value));
|
||||
}
|
||||
}
|
||||
|
||||
t.ReadSymbol('}');
|
||||
return group;
|
||||
}
|
||||
}
|
||||
53
007SaveTool/VdfGenerator/KeyValue/KeyValueSerializer.cs
Normal file
53
007SaveTool/VdfGenerator/KeyValue/KeyValueSerializer.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using EonaCat.FirstLight.SaveTransfer.VdfGenerator.KeyValue.Models;
|
||||
using System.Text;
|
||||
|
||||
namespace EonaCat.FirstLight.SaveTransfer.VdfGenerator.KeyValue;
|
||||
|
||||
/// <summary>
|
||||
/// Provides functionality to serialize key–value groups into a text-based format.
|
||||
/// </summary>
|
||||
public class KeyValueSerializer
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializes the given key–value group into a text format.
|
||||
/// </summary>
|
||||
/// <param name="group">The key–value group to serialize. Cannot be null.</param>
|
||||
/// <returns>A string representing the serialized form of the key–value group.</returns>
|
||||
public static string Serialize(KeyValueGroup group)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
SerializeGroup(group, sb, 0);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified key-value group and its child elements into a formatted string representation, appending the result to the provided StringBuilder.
|
||||
/// </summary>
|
||||
/// <param name="group">The key-value group to serialize. Cannot be null.</param>
|
||||
/// <param name="sb">The StringBuilder to which the serialized output is appended. Cannot be null.</param>
|
||||
/// <param name="indent">The indentation level to apply to the serialized output.</param>
|
||||
private static void SerializeGroup(KeyValueGroup group, StringBuilder sb, int indent)
|
||||
{
|
||||
const char padChar = '\t';
|
||||
var pad = new string(padChar, indent);
|
||||
|
||||
sb.Append($"{pad}\"{group.Key}\"\n");
|
||||
sb.Append($"{pad}{{\n");
|
||||
|
||||
foreach (var node in group.Nodes)
|
||||
{
|
||||
switch (node)
|
||||
{
|
||||
case Models.KeyValuePair pair:
|
||||
sb.Append($"{pad}{padChar}\"{pair.Key}\"{padChar}{padChar}\"{pair.Value}\"\n");
|
||||
break;
|
||||
|
||||
case KeyValueGroup childGroup:
|
||||
SerializeGroup(childGroup, sb, indent + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append($"{pad}}}\n");
|
||||
}
|
||||
}
|
||||
81
007SaveTool/VdfGenerator/KeyValue/KeyValueTokenizer.cs
Normal file
81
007SaveTool/VdfGenerator/KeyValue/KeyValueTokenizer.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
namespace EonaCat.FirstLight.SaveTransfer.VdfGenerator.KeyValue;
|
||||
|
||||
/// <summary>
|
||||
/// Provides functionality for tokenizing a key-value formatted string input, allowing sequential reading and validation of symbols and quoted strings.
|
||||
/// </summary>
|
||||
/// <param name="text">The input string to tokenize. Must not be null.</param>
|
||||
public class KeyValueTokenizer(string text)
|
||||
{
|
||||
private int _pos;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the next non-whitespace character in the input matches the specified character without advancing the current position.
|
||||
/// </summary>
|
||||
/// <param name="c">The character to compare with the next non-whitespace character in the input.</param>
|
||||
/// <returns><see langword="true"/> if the next non-whitespace character matches the specified character; otherwise, <see langword="false"/>.</returns>
|
||||
public bool PeekSymbol(char c)
|
||||
{
|
||||
SkipWhitespace();
|
||||
return _pos < text.Length && text[_pos] == c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next non-whitespace character from the input and verifies that it matches the specified symbol.
|
||||
/// </summary>
|
||||
/// <param name="c">The character to match at the current position in the input.</param>
|
||||
/// <exception cref="Exception">Thrown if the next non-whitespace character does not match the specified symbol.</exception>
|
||||
public void ReadSymbol(char c)
|
||||
{
|
||||
SkipWhitespace();
|
||||
if (_pos >= text.Length || text[_pos] != c)
|
||||
throw new Exception($"Expected '{c}' at position {_pos}");
|
||||
|
||||
_pos++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a string enclosed in quotation marks from the current position in the input text.
|
||||
/// </summary>
|
||||
/// <returns> The string located between the opening and closing quotation marks or an empty string if there are no characters between the quotes. </returns>
|
||||
/// <exception cref="Exception"> Thrown when the current position does not contain an opening quotation mark or when a closing quotation mark cannot be found. </exception>
|
||||
public string ReadString()
|
||||
{
|
||||
SkipWhitespace();
|
||||
|
||||
if (_pos >= text.Length || text[_pos] != '"')
|
||||
throw new Exception($"Expected '\"' at position {_pos}, but found '{text[_pos]}'!");
|
||||
|
||||
_pos++; // skip opening quote
|
||||
var start = _pos;
|
||||
|
||||
while (_pos < text.Length && text[_pos] != '"')
|
||||
_pos++;
|
||||
|
||||
if (_pos >= text.Length)
|
||||
throw new Exception("Unterminated string literal!");
|
||||
|
||||
var result = text.Substring(start, _pos - start);
|
||||
_pos++; // skip closing quote
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the current position past any consecutive whitespace characters in the input text.
|
||||
/// </summary>
|
||||
private void SkipWhitespace()
|
||||
{
|
||||
while (_pos < text.Length)
|
||||
{
|
||||
var c = text[_pos];
|
||||
|
||||
if (c is ' ' or '\t' or '\n' or '\r')
|
||||
{
|
||||
_pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
007SaveTool/VdfGenerator/KeyValue/Models/KeyValueGroup.cs
Normal file
36
007SaveTool/VdfGenerator/KeyValue/Models/KeyValueGroup.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using EonaCat.FirstLight.SaveTransfer.VdfGenerator.KeyValue.Interfaces;
|
||||
|
||||
namespace EonaCat.FirstLight.SaveTransfer.VdfGenerator.KeyValue.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a hierarchical group of key-value nodes, allowing organization of nested key-value pairs and groups.
|
||||
/// </summary>
|
||||
/// <param name="key">The key that identifies this group. Cannot be null.</param>
|
||||
public class KeyValueGroup(string key) : IKeyValueNode
|
||||
{
|
||||
public string Key { get; } = key;
|
||||
public List<IKeyValueNode> Nodes { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new key-value pair to the group.
|
||||
/// </summary>
|
||||
/// <param name="key">The key to associate with the value. Cannot be null.</param>
|
||||
/// <param name="value">The value to associate with the key. Cannot be null.</param>
|
||||
/// <returns>The current instance with the new key-value pair added.</returns>
|
||||
public KeyValueGroup Add(string key, string value)
|
||||
{
|
||||
Nodes.Add(new KeyValuePair(key, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified group to the collection of nodes.
|
||||
/// </summary>
|
||||
/// <param name="group">The group to add to the collection. Cannot be null.</param>
|
||||
/// <returns>The current instance with the added group, enabling method chaining.</returns>
|
||||
public KeyValueGroup Add(KeyValueGroup group)
|
||||
{
|
||||
Nodes.Add(group);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
14
007SaveTool/VdfGenerator/KeyValue/Models/KeyValuePair.cs
Normal file
14
007SaveTool/VdfGenerator/KeyValue/Models/KeyValuePair.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using EonaCat.FirstLight.SaveTransfer.VdfGenerator.KeyValue.Interfaces;
|
||||
|
||||
namespace EonaCat.FirstLight.SaveTransfer.VdfGenerator.KeyValue.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a key-value pair node with immutable key and value properties.
|
||||
/// </summary>
|
||||
/// <param name="key">The key associated with the pair. If not specified, an empty string is used.</param>
|
||||
/// <param name="value">The value associated with the pair. If not specified, an empty string is used.</param>
|
||||
public class KeyValuePair(string key = "", string value = "") : IKeyValueNode
|
||||
{
|
||||
public string Key { get; } = key;
|
||||
public string Value { get; } = value;
|
||||
}
|
||||
Reference in New Issue
Block a user