-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVmfParser.cs
More file actions
147 lines (118 loc) · 3.77 KB
/
Copy pathVmfParser.cs
File metadata and controls
147 lines (118 loc) · 3.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
using System.Text;
namespace Vmf2Map;
internal static class VmfParser
{
public static List<VmfNode> Parse(string text)
{
var position = 0;
var roots = new List<VmfNode>();
while (true)
{
SkipWhitespaceAndComments(text, ref position);
if (position >= text.Length)
{
break;
}
var name = ReadName(text, ref position);
roots.Add(ReadBlock(text, ref position, name));
}
return roots;
}
private static VmfNode ReadBlock(string text, ref int position, string name)
{
SkipWhitespaceAndComments(text, ref position);
Expect(text, ref position, '{');
var node = new VmfNode(name);
while (true)
{
SkipWhitespaceAndComments(text, ref position);
if (position >= text.Length)
{
throw new FormatException($"Unexpected end of file inside block '{name}'.");
}
var c = text[position];
if (c == '}')
{
position++;
return node;
}
if (c == '"')
{
var key = ReadQuoted(text, ref position);
SkipWhitespaceAndComments(text, ref position);
if (position >= text.Length || text[position] != '"')
{
throw new FormatException($"Expected a value after key '{key}' in block '{name}'.");
}
var value = ReadQuoted(text, ref position);
node.Properties.Add(new KeyValuePair<string, string>(key, value));
continue;
}
var childName = ReadName(text, ref position);
node.Children.Add(ReadBlock(text, ref position, childName));
}
}
private static void SkipWhitespaceAndComments(string text, ref int position)
{
while (position < text.Length)
{
var c = text[position];
if (char.IsWhiteSpace(c))
{
position++;
continue;
}
if (c == '/' && position + 1 < text.Length && text[position + 1] == '/')
{
while (position < text.Length && text[position] != '\n')
{
position++;
}
continue;
}
return;
}
}
private static string ReadQuoted(string text, ref int position)
{
position++;
var builder = new StringBuilder();
while (position < text.Length)
{
var c = text[position++];
if (c == '\\' && position < text.Length && text[position] == '"')
{
builder.Append('"');
position++;
continue;
}
if (c == '"')
{
return builder.ToString();
}
builder.Append(c);
}
throw new FormatException("Unterminated quoted string.");
}
private static string ReadName(string text, ref int position)
{
var start = position;
while (position < text.Length && !char.IsWhiteSpace(text[position]) && text[position] != '{' && text[position] != '}')
{
position++;
}
if (position == start)
{
throw new FormatException($"Expected a block name at offset {position}.");
}
return text[start..position];
}
private static void Expect(string text, ref int position, char expected)
{
if (position >= text.Length || text[position] != expected)
{
throw new FormatException($"Expected '{expected}' at offset {position}.");
}
position++;
}
}