forked from paviad/GoSharp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SGFProperty.cs
141 lines (125 loc) · 4.41 KB
/
SGFProperty.cs
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace Go
{
/// <summary>
/// Represents an SGF property, see the SGF specification at
/// <a href="http://www.red-bean.com/sgf">http://www.red-bean.com/sgf</a>
/// </summary>
public class SGFProperty
{
/// <summary>
/// Contains the property name.
/// </summary>
public string Name;
/// <summary>
/// Contains a list of SGF property-value objects.
/// </summary>
public List<SGFPropValue> Values = new List<SGFPropValue>();
/// <summary>
/// Returns true if this property is a move property.
/// </summary>
public bool IsMove { get { return Name == "W" || Name == "B"; } }
/// <summary>
/// Returns true if this property is a setup property.
/// </summary>
public bool IsSetup { get { return Name == "AE" || Name == "AB" || Name == "AW" || Name == "PL"; } }
private HashSet<string> moveProperties = new HashSet<string>
{
"W","B","AB","AW","AE"
};
/// <summary>
/// Returns true if this property is a file format property.
/// </summary>
public bool IsRoot
{
get
{
return !moveProperties.Contains(Name);
}
}
/// <summary>
/// Returns the property priority when writing an SGF file.
/// </summary>
public int Priority
{
get
{
if (IsRoot) return 0;
if (IsSetup) return 1;
if (IsMove) return 2;
return 3;
}
}
internal void Read(TextReader sr)
{
char c;
Name = "";
sr.EatWS();
while (char.IsUpper((char)sr.Peek()))
{
c = (char)sr.Read();
Name += c;
}
sr.EatWS();
while (sr.Peek() == '[')
{
ReadValue(sr);
sr.EatWS();
}
}
private void ReadValue (TextReader sr)
{
char c = (char) sr.Read ();
if (c != '[')
throw new InvalidDataException ("Property value doesn't begin with a '['.");
bool verbatim = false;
var sb = new StringBuilder ();
for (; ; ) {
c = (char) sr.Read ();
/* Spec 3.2. Text/Formatting
* Formatting:
* Soft line break: linebreaks preceded by a "\" (soft linebreaks are converted to "", i.e. they are removed)
* Hard line breaks: any other linebreaks encountered
*
* Attention: a single linebreak is represented differently on different systems, e.g. "LFCR" for DOS, "LF" on Unix. An application should be able to deal with following linebreaks: LF, CR, LFCR, CRLF.
* [...]
* Escaping: "\" is the escape character. Any char following "\" is inserted verbatim (exception: whitespaces still have to be converted to space!). Following chars have to be escaped, when used in Text: "]", "\" and ":" (only if used in compose data type).
*/
if (verbatim) {
if (c == '\r' || c == '\n') {
var next = sr.Peek ();
if (next != c && (next == '\r' || next == '\n')) {
sr.Read ();
}
}
else {
if (char.IsWhiteSpace (c)) {
c = ' ';
}
sb.Append (c);
}
verbatim = false;
continue;
}
if (c == '\\') {
verbatim = true;
continue;
}
if (c == ']') {
break;
}
sb.Append (c);
}
Values.Add (new SGFPropValue (sb.ToString ()));
}
public override string ToString ()
{
var vs = Values.Select (v => v.ToString ()).ToArray ();
return Name + ":" + string.Join (", ", vs);
}
}
}