Files
CVRManager/Services/Vdf.cs
T
Exterrata 9bb4f85802 CVR Manager 1.0.0
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 02:46:35 -04:00

100 lines
3.0 KiB
C#

using System.Text;
namespace CVRManager.Services;
public static class Vdf
{
public static Dictionary<string, object> Parse(string text, int start = 0)
{
var pos = start;
var root = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
var key = ReadToken(text, ref pos);
if (key == null) return root;
var next = Peek(text, pos);
if (next == '{')
{
pos = text.IndexOf('{', pos) + 1;
root[key] = ParseBlock(text, ref pos);
}
return root;
}
public static Dictionary<string, object> ParseDocument(string text)
{
var pos = 0;
return ParseBlock(text, ref pos, true);
}
static Dictionary<string, object> ParseBlock(string text, ref int pos, bool toEnd = false)
{
var dict = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
while (true)
{
SkipSpace(text, ref pos);
if (pos >= text.Length) return dict;
if (text[pos] == '}')
{
pos++;
return dict;
}
var key = ReadToken(text, ref pos);
if (key == null) return dict;
SkipSpace(text, ref pos);
if (pos < text.Length && text[pos] == '{')
{
pos++;
dict[key] = ParseBlock(text, ref pos);
}
else
{
var val = ReadToken(text, ref pos);
if (val == null) return dict;
dict[key] = val;
}
}
}
static char Peek(string text, int pos)
{
SkipSpace(text, ref pos);
return pos < text.Length ? text[pos] : '\0';
}
static void SkipSpace(string text, ref int pos)
{
while (pos < text.Length)
{
if (char.IsWhiteSpace(text[pos])) pos++;
else if (text[pos] == '/' && pos + 1 < text.Length && text[pos + 1] == '/')
while (pos < text.Length && text[pos] != '\n') pos++;
else break;
}
}
static string? ReadToken(string text, ref int pos)
{
SkipSpace(text, ref pos);
if (pos >= text.Length || text[pos] != '"') return null;
pos++;
var sb = new StringBuilder();
while (pos < text.Length && text[pos] != '"')
{
if (text[pos] == '\\' && pos + 1 < text.Length)
{
pos++;
sb.Append(text[pos] switch { 'n' => '\n', 't' => '\t', var c => c });
}
else sb.Append(text[pos]);
pos++;
}
pos++;
return sb.ToString();
}
public static Dictionary<string, object>? Dict(this Dictionary<string, object> d, string key) =>
d.TryGetValue(key, out var v) ? v as Dictionary<string, object> : null;
public static string Str(this Dictionary<string, object> d, string key) =>
d.TryGetValue(key, out var v) && v is string s ? s : "";
}