-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathShapeBuilder.cs
222 lines (182 loc) · 7.62 KB
/
ShapeBuilder.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
using System;
using System.Linq;
using System.Windows.Markup;
using System.Windows.Media;
using System.Xml;
using System.Xml.Linq;
namespace PdnCodeLab
{
internal static class ShapeBuilder
{
private static Error error;
internal static Error Error => error;
internal static bool TryParseShapeCode(string shapeCode)
{
Geometry geometry = GeometryFromRawString(shapeCode);
return geometry != null;
}
internal static bool TryExtractShapeName(string shapeCode, out string shapeName)
{
shapeName = null;
if (string.IsNullOrWhiteSpace(shapeCode))
{
return false;
}
XDocument xDoc = TryParseXDocument(shapeCode);
if (xDoc == null)
{
return false;
}
XElement docElement = xDoc.Root;
if (docElement.Name.LocalName != "SimpleGeometryShape" || !docElement.HasAttributes)
{
return false;
}
XAttribute nameAttribute = docElement.Attribute("DisplayName");
if (nameAttribute == null || string.IsNullOrWhiteSpace(nameAttribute.Value))
{
return false;
}
shapeName = nameAttribute.Value;
return shapeName != null;
}
internal static Geometry GeometryFromRawString(string shapeCode)
{
error = null;
if (string.IsNullOrWhiteSpace(shapeCode))
{
error = Error.NewShapeError(0, 0, "Shape code is invalid or otherwise unrecognized.");
return null;
}
XDocument xDoc = TryParseXDocument(shapeCode);
if (xDoc == null)
{
return null;
}
XElement docElement = xDoc.Root;
if (docElement.Name.LocalName != "SimpleGeometryShape")
{
IXmlLineInfo lineInfo = docElement;
error = Error.NewShapeError(lineInfo.LineNumber, 0, "The root element must be SimpleGeometryShape.");
return null;
}
if (!docElement.HasAttributes)
{
IXmlLineInfo lineInfo = docElement;
error = Error.NewShapeError(lineInfo.LineNumber, 0, "The SimpleGeometryShape element is missing attributes.");
return null;
}
XAttribute nameAttribute = docElement.Attribute(XName.Get("DisplayName", string.Empty));
if (nameAttribute == null)
{
IXmlLineInfo lineInfo = docElement;
error = Error.NewShapeError(lineInfo.LineNumber, 0, "The DisplayName attribute is missing.");
}
else if (string.IsNullOrWhiteSpace(nameAttribute.Value))
{
IXmlLineInfo lineInfo = nameAttribute;
error = Error.NewShapeError(lineInfo.LineNumber, 0, "The DisplayName attribute is empty.");
}
XAttribute geometryAttribute = docElement.Attribute(XName.Get("Geometry", string.Empty));
if (docElement.HasElements)
{
if (geometryAttribute != null)
{
IXmlLineInfo lineInfo = geometryAttribute;
error = Error.NewShapeError(lineInfo.LineNumber, 0, "Can not contain both Geometry attribute and child elements.");
return null;
}
XElement firstElement = docElement.Elements().First();
if (firstElement.ElementsAfterSelf().Any())
{
IXmlLineInfo lineInfo = firstElement.ElementsAfterSelf().First();
error = Error.NewShapeError(lineInfo.LineNumber, 0, "There can only be one child element of SimpleGeometryShape.");
return null;
}
if (!Intelli.XamlAutoCompleteTypes.TryGetValue(firstElement.Name.LocalName, out Type type) ||
!type.IsSubclassOf(typeof(Geometry)))
{
IXmlLineInfo lineInfo = firstElement;
error = Error.NewShapeError(lineInfo.LineNumber, 0, "The child element of SimpleGeometryShape must be a Geometry-derived class.");
return null;
}
string xElementText = firstElement.ToString();
int xmlnsStartIndex = xElementText.IndexOf(" xmlns=", StringComparison.Ordinal);
int xmlnsEndIndex = xElementText.IndexOf(">", StringComparison.Ordinal);
if (firstElement.IsEmpty)
{
xmlnsEndIndex--;
}
if (xmlnsStartIndex < 0 || xmlnsEndIndex < 0 || xmlnsEndIndex < xmlnsStartIndex)
{
error = Error.NewShapeError(0, 0, "Shape code is invalid or otherwise unrecognized.");
return null;
}
const string xamlNs = " xmlns =\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"";
IXmlLineInfo offsetPos = firstElement;
string whiteSpace = new string('\n', offsetPos.LineNumber - 1) + new string(' ', offsetPos.LinePosition - 2);
string geometryText = xElementText
.Remove(xmlnsStartIndex, xmlnsEndIndex - xmlnsStartIndex)
.Insert(xmlnsStartIndex, xamlNs)
.Insert(0, whiteSpace);
return TryParseGeometry(geometryText);
}
else
{
if (geometryAttribute == null)
{
error = Error.NewShapeError(0, 0, "Can not find the Geometry attribute.");
return null;
}
string geometryText = geometryAttribute.Value;
if (string.IsNullOrWhiteSpace(geometryText))
{
IXmlLineInfo lineInfo = geometryAttribute;
error = Error.NewShapeError(lineInfo.LineNumber, 0, "The Geometry attribute is empty.");
return null;
}
return TryParseStreamGeometry(geometryText);
}
}
private static XDocument TryParseXDocument(string xDocumentText)
{
XDocument xDocument = null;
try
{
xDocument = XDocument.Parse(xDocumentText, LoadOptions.SetLineInfo | LoadOptions.PreserveWhitespace);
}
catch (XmlException ex)
{
error = Error.NewShapeError(ex.LineNumber, ex.LinePosition, ex.Message);
return null;
}
return xDocument;
}
private static Geometry TryParseGeometry(string geometryText)
{
Geometry geometry = null;
try
{
geometry = (Geometry)XamlReader.Parse(geometryText);
}
catch (XamlParseException ex)
{
error = Error.NewShapeError(ex.LineNumber, ex.LinePosition, ex.Message);
}
return geometry;
}
private static StreamGeometry TryParseStreamGeometry(string streamGeometryText)
{
StreamGeometry streamGeometry = null;
try
{
streamGeometry = (StreamGeometry)Geometry.Parse(streamGeometryText);
}
catch (FormatException ex)
{
error = Error.NewShapeError(0, 0, ex.Message);
}
return streamGeometry;
}
}
}