Skip to content

Commit

Permalink
Add VDF
Browse files Browse the repository at this point in the history
  • Loading branch information
cooolbros committed Nov 2, 2023
1 parent c2bce80 commit ed02275
Show file tree
Hide file tree
Showing 9 changed files with 413 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/HUDMerger.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HUDMerger", "HUDMerger\HUDM
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HUDMergerTests", "HUDMergerTests\HUDMergerTests.csproj", "{636E43CE-24FD-4F54-860B-8E442ACC0318}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDF", "VDF\VDF.csproj", "{1C8FB3B7-478B-40AF-87B4-EBBD422E49F6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -41,6 +43,18 @@ Global
{636E43CE-24FD-4F54-860B-8E442ACC0318}.Release|x64.Build.0 = Release|Any CPU
{636E43CE-24FD-4F54-860B-8E442ACC0318}.Release|x86.ActiveCfg = Release|Any CPU
{636E43CE-24FD-4F54-860B-8E442ACC0318}.Release|x86.Build.0 = Release|Any CPU
{1C8FB3B7-478B-40AF-87B4-EBBD422E49F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1C8FB3B7-478B-40AF-87B4-EBBD422E49F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1C8FB3B7-478B-40AF-87B4-EBBD422E49F6}.Debug|x64.ActiveCfg = Debug|Any CPU
{1C8FB3B7-478B-40AF-87B4-EBBD422E49F6}.Debug|x64.Build.0 = Debug|Any CPU
{1C8FB3B7-478B-40AF-87B4-EBBD422E49F6}.Debug|x86.ActiveCfg = Debug|Any CPU
{1C8FB3B7-478B-40AF-87B4-EBBD422E49F6}.Debug|x86.Build.0 = Debug|Any CPU
{1C8FB3B7-478B-40AF-87B4-EBBD422E49F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1C8FB3B7-478B-40AF-87B4-EBBD422E49F6}.Release|Any CPU.Build.0 = Release|Any CPU
{1C8FB3B7-478B-40AF-87B4-EBBD422E49F6}.Release|x64.ActiveCfg = Release|Any CPU
{1C8FB3B7-478B-40AF-87B4-EBBD422E49F6}.Release|x64.Build.0 = Release|Any CPU
{1C8FB3B7-478B-40AF-87B4-EBBD422E49F6}.Release|x86.ActiveCfg = Release|Any CPU
{1C8FB3B7-478B-40AF-87B4-EBBD422E49F6}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
12 changes: 12 additions & 0 deletions src/VDF/Exceptions/VDFSyntaxException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using System.Diagnostics.CodeAnalysis;
using VDF.Models;

namespace VDF.Exceptions;

public class VDFSyntaxException : Exception
{
public VDFSyntaxException(VDFToken? unexpected, string[] expected, int index, int line, int character) : base($"Unexpected {(unexpected != null ? $"{unexpected?.Type} '{unexpected?.Value}'" : "EOF")} at position {index} (line {line + 1}, character {character + 1}). Expected {string.Join(" | ", expected)}.")
{
}
}
10 changes: 10 additions & 0 deletions src/VDF/Models/KeyValue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace VDF.Models;

public readonly record struct KeyValue
{
public required string Key { get; init; }
public required dynamic Value { get; init; }
public required string? Conditional { get; init; }
}
8 changes: 8 additions & 0 deletions src/VDF/Models/KeyValues.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System;
using System.Collections.Generic;

namespace VDF.Models;

public class KeyValues : List<KeyValue>
{
}
9 changes: 9 additions & 0 deletions src/VDF/Models/VDFToken.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;

namespace VDF.Models;

public readonly record struct VDFToken
{
public required VDFTokenType Type { get; init; }
public required string Value { get; init; }
}
10 changes: 10 additions & 0 deletions src/VDF/Models/VDTTokenType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace VDF.Models;

public enum VDFTokenType : byte
{
String,
Conditional,
ControlCharacter,
}
8 changes: 8 additions & 0 deletions src/VDF/VDF.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
132 changes: 132 additions & 0 deletions src/VDF/VDFSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
using System;
using VDF.Exceptions;
using VDF.Models;

namespace VDF;

public static class VDFSerializer
{
public static KeyValues Deserialize(string str)
{
VDFTokeniser tokeniser = new(str);

static KeyValues ReadKeyValues(VDFTokeniser tokeniser, bool isObject)
{
KeyValues keyValues = new();

while (true)
{
KeyValue? keyValue = tokeniser.Read() switch
{
{ Type: VDFTokenType.ControlCharacter, Value: "}" } when isObject => null,
null when !isObject => null,
null => throw new VDFSyntaxException(
null,
new[] { "key" },
tokeniser.Index,
tokeniser.Line,
tokeniser.Character
),
{ Type: VDFTokenType.String } token => ReadKeyValue(tokeniser, token.Value),
VDFToken token => throw new VDFSyntaxException(
token,
new[] { "key" },
tokeniser.Index,
tokeniser.Line,
tokeniser.Character
),
};

if (keyValue == null)
{
break;
}

keyValues.Add(keyValue.Value);
}

return keyValues;
}

static KeyValue ReadKeyValue(VDFTokeniser tokeniser, string key)
{
VDFToken? valueToken = tokeniser.Read();

string? conditional;

if (valueToken is { Type: VDFTokenType.Conditional })
{
conditional = valueToken.Value.Value;
valueToken = tokeniser.Read();
}
else
{
conditional = null;
}

return valueToken switch
{
{ Type: VDFTokenType.ControlCharacter, Value: "{" } => new KeyValue
{
Key = key,
Value = ReadKeyValues(tokeniser, true),
Conditional = conditional,
},
{ Type: VDFTokenType.String } token => new KeyValue
{
Key = key,
Value = token.Value,
Conditional = ReadConditional(tokeniser) ?? conditional,
},
VDFToken token => throw new VDFSyntaxException(
token,
new[] { "value", "{" },
tokeniser.Index,
tokeniser.Line,
tokeniser.Character
),
null => throw new VDFSyntaxException(
null,
new[] { "value", "{" },
tokeniser.Index,
tokeniser.Line,
tokeniser.Character
),
};
}

static string? ReadConditional(VDFTokeniser tokeniser)
{
if (tokeniser.Read(true) is { Type: VDFTokenType.Conditional } token)
{
tokeniser.Read();
return token.Value;
}

return null;
}

return ReadKeyValues(tokeniser, false);
}

public static string Serialize(KeyValues keyValues, int level = 0)
{
string str = "";

foreach (KeyValue keyValue in keyValues)
{
if (keyValue.Value is KeyValues kvs)
{
str += $"{new string('\t', level)}\"{keyValue.Key}\"{(keyValue.Conditional != null ? $" {keyValue.Conditional}" : "")}\r\n";
str += $"{new string('\t', level)}{{\r\n";
str += $"{Serialize(kvs, level + 1)}{new string('\t', level)}}}\r\n";
}
else if (keyValue.Value is string value)
{
str += $"{new string('\t', level)}\"{keyValue.Key}\"\t\"{value}\"{(keyValue.Conditional != null ? $" {keyValue.Conditional}" : "")}\r\n";
}
}

return str;
}
}
Loading

0 comments on commit ed02275

Please sign in to comment.