Skip to content

Commit 3ec496e

Browse files
committed
Treat names and strings the same in the SerialisedObjectFormatter
Fixes #41
1 parent 3a817fb commit 3ec496e

File tree

3 files changed

+61
-8
lines changed

3 files changed

+61
-8
lines changed

Sledge.Formats.Tests/Valve/TestSerialisedObject.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,44 @@ public void TestNestedObjectsWithQuotedNames()
211211
Assert.AreEqual("Three", output[0].Children[0].Children[0].Name);
212212
Assert.AreEqual("Value", output[0].Children[0].Children[0].Get<string>("Key"));
213213
}
214+
215+
[TestMethod]
216+
public void TestSpecialCharactersInKeyValues()
217+
{
218+
var input = """
219+
One
220+
{
221+
$key1 "$value1"
222+
$key2 $value2
223+
!key3 &value3
224+
!@#$%^&*()_+ value4
225+
A B
226+
"C" D
227+
E "F"
228+
"G" "H"
229+
$I { }
230+
"$J" { }
231+
}
232+
""";
233+
234+
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(input));
235+
var fmt = new SerialisedObjectFormatter();
236+
var output = fmt.Deserialize(stream).ToList();
237+
238+
Assert.AreEqual(1, output.Count);
239+
Assert.AreEqual("One", output[0].Name);
240+
Assert.AreEqual("$value1", output[0].Get<string>("$key1"));
241+
Assert.AreEqual("$value2", output[0].Get<string>("$key2"));
242+
Assert.AreEqual("&value3", output[0].Get<string>("!key3"));
243+
Assert.AreEqual("value4", output[0].Get<string>("!@#$%^&*()_+"));
244+
Assert.AreEqual("B", output[0].Get<string>("A"));
245+
Assert.AreEqual("D", output[0].Get<string>("C"));
246+
Assert.AreEqual("F", output[0].Get<string>("E"));
247+
Assert.AreEqual("H", output[0].Get<string>("G"));
248+
Assert.AreEqual(2, output[0].Children.Count);
249+
Assert.AreEqual("$I", output[0].Children[0].Name);
250+
Assert.AreEqual(0, output[0].Children[0].Children.Count);
251+
Assert.AreEqual("$J", output[0].Children[1].Name);
252+
Assert.AreEqual(0, output[0].Children[1].Children.Count);
253+
}
214254
}

Sledge.Formats/Sledge.Formats.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
<RepositoryUrl>https://github.com/LogicAndTrick/sledge-formats</RepositoryUrl>
1414
<RepositoryType>Git</RepositoryType>
1515
<PackageTags>half-life quake valve liblist vdf</PackageTags>
16-
<PackageReleaseNotes>Additions to the IFileSystem interface</PackageReleaseNotes>
16+
<PackageReleaseNotes>Fix parsing issues when serialised object keys/values are unquoted and contain special characters</PackageReleaseNotes>
1717
<PackageLicenseFile></PackageLicenseFile>
1818
<PackageLicenseExpression>MIT</PackageLicenseExpression>
19-
<Version>1.3.0</Version>
19+
<Version>1.3.1</Version>
2020
</PropertyGroup>
2121

2222
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">

Sledge.Formats/Valve/SerialisedObjectFormatter.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Linq;
55
using System.Text;
66
using Sledge.Formats.Tokens;
7+
using Sledge.Formats.Tokens.Readers;
78

89
namespace Sledge.Formats.Valve
910
{
@@ -112,7 +113,23 @@ public static void Print(SerialisedObject obj, TextWriter tw, int tabs = 0)
112113
Tokens.Symbols.CloseBrace
113114
};
114115

115-
private static readonly Tokeniser Tokeniser = new Tokeniser(Symbols);
116+
private static readonly Tokeniser Tokeniser;
117+
118+
static SerialisedObjectFormatter()
119+
{
120+
Tokeniser = new Tokeniser(
121+
new SingleLineCommentTokenReader(),
122+
new StringTokenReader(),
123+
new UnsignedIntegerTokenReader(),
124+
new SymbolTokenReader(Symbols),
125+
new NameTokenReader(IsValidNameCharacter, IsValidNameCharacter)
126+
);
127+
}
128+
129+
private static bool IsValidNameCharacter(char c)
130+
{
131+
return c != '"' && c != '{' && c != '}' && !char.IsWhiteSpace(c) && !char.IsControl(c);
132+
}
116133

117134
/// <summary>
118135
/// Parse a structure from a stream
@@ -182,7 +199,7 @@ public static IEnumerable<SerialisedObject> Parse(TextReader reader)
182199

183200
break;
184201
}
185-
else if (t.Type == TokenType.String && it.Current.Type == TokenType.String)
202+
else if (it.Current.Type == TokenType.String || it.Current.Type == TokenType.Name)
186203
{
187204
if (current == null) throw new TokenParsingException(t, "No structure to add key/values to");
188205

@@ -192,10 +209,6 @@ public static IEnumerable<SerialisedObject> Parse(TextReader reader)
192209

193210
break;
194211
}
195-
else if (t.Type == TokenType.Name)
196-
{
197-
throw new TokenParsingException(t, "Expected structure open brace");
198-
}
199212
else
200213
{
201214
throw new TokenParsingException(t, "Expected string value or open brace to follow string key");

0 commit comments

Comments
 (0)