diff options
Diffstat (limited to 'src/WixToolset.Data/IntermediateSymbol.cs')
-rw-r--r-- | src/WixToolset.Data/IntermediateSymbol.cs | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/src/WixToolset.Data/IntermediateSymbol.cs b/src/WixToolset.Data/IntermediateSymbol.cs new file mode 100644 index 00000000..4030df5d --- /dev/null +++ b/src/WixToolset.Data/IntermediateSymbol.cs | |||
@@ -0,0 +1,256 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
2 | |||
3 | namespace WixToolset.Data | ||
4 | { | ||
5 | using System; | ||
6 | using System.Diagnostics; | ||
7 | using SimpleJson; | ||
8 | |||
9 | [DebuggerDisplay("{DebuggerDisplay,nq}")] | ||
10 | public class IntermediateSymbol | ||
11 | { | ||
12 | private object tags; | ||
13 | |||
14 | public IntermediateSymbol(IntermediateSymbolDefinition definition) : this(definition, null, null) | ||
15 | { | ||
16 | } | ||
17 | |||
18 | public IntermediateSymbol(IntermediateSymbolDefinition definition, SourceLineNumber sourceLineNumber, Identifier id = null) | ||
19 | { | ||
20 | this.Definition = definition; | ||
21 | this.Fields = new IntermediateField[definition.FieldDefinitions.Length]; | ||
22 | this.SourceLineNumbers = sourceLineNumber; | ||
23 | this.Id = id; | ||
24 | } | ||
25 | |||
26 | public IntermediateSymbolDefinition Definition { get; } | ||
27 | |||
28 | public IntermediateField[] Fields { get; } | ||
29 | |||
30 | public SourceLineNumber SourceLineNumbers { get; set; } | ||
31 | |||
32 | public Identifier Id { get; set; } | ||
33 | |||
34 | public IntermediateField this[int index] => this.Fields[index]; | ||
35 | |||
36 | private string DebuggerDisplay => $"{this.Definition?.Name} {this.Id?.Id}"; | ||
37 | |||
38 | public bool AddTag(string add) | ||
39 | { | ||
40 | if (this.tags == null) | ||
41 | { | ||
42 | this.tags = add; | ||
43 | } | ||
44 | else if (this.tags is string tag) | ||
45 | { | ||
46 | if (tag == add) | ||
47 | { | ||
48 | return false; | ||
49 | } | ||
50 | |||
51 | this.tags = new[] { tag, add }; | ||
52 | } | ||
53 | else | ||
54 | { | ||
55 | var tagsArray = (string[])this.tags; | ||
56 | var array = new string[tagsArray.Length + 1]; | ||
57 | |||
58 | for (var i = 0; i < tagsArray.Length; ++i) | ||
59 | { | ||
60 | if (tagsArray[i] == add) | ||
61 | { | ||
62 | return false; | ||
63 | } | ||
64 | |||
65 | array[i] = tagsArray[i]; | ||
66 | } | ||
67 | |||
68 | array[tagsArray.Length] = add; | ||
69 | |||
70 | this.tags = array; | ||
71 | } | ||
72 | |||
73 | return true; | ||
74 | } | ||
75 | |||
76 | public bool HasTag(string has) | ||
77 | { | ||
78 | if (this.tags == null) | ||
79 | { | ||
80 | return false; | ||
81 | } | ||
82 | else if (this.tags is string tag) | ||
83 | { | ||
84 | return tag == has; | ||
85 | } | ||
86 | else | ||
87 | { | ||
88 | foreach (var element in (string[])this.tags) | ||
89 | { | ||
90 | if (element == has) | ||
91 | { | ||
92 | return true; | ||
93 | } | ||
94 | } | ||
95 | } | ||
96 | |||
97 | return false; | ||
98 | } | ||
99 | |||
100 | public bool RemoveTag(string remove) | ||
101 | { | ||
102 | if (this.tags is string tag) | ||
103 | { | ||
104 | if (tag == remove) | ||
105 | { | ||
106 | this.tags = null; | ||
107 | return true; | ||
108 | } | ||
109 | } | ||
110 | else if (this.tags is string[] tagsArray) | ||
111 | { | ||
112 | if (tagsArray.Length == 2) | ||
113 | { | ||
114 | if (tagsArray[0] == remove) | ||
115 | { | ||
116 | this.tags = tagsArray[1]; | ||
117 | return true; | ||
118 | } | ||
119 | else if (tagsArray[1] == remove) | ||
120 | { | ||
121 | this.tags = tagsArray[0]; | ||
122 | return true; | ||
123 | } | ||
124 | } | ||
125 | else | ||
126 | { | ||
127 | var array = new string[tagsArray.Length - 1]; | ||
128 | var arrayIndex = 0; | ||
129 | var found = false; | ||
130 | |||
131 | for (var i = 0; i < tagsArray.Length; ++i) | ||
132 | { | ||
133 | if (tagsArray[i] == remove) | ||
134 | { | ||
135 | found = true; | ||
136 | continue; | ||
137 | } | ||
138 | else if (arrayIndex == array.Length) | ||
139 | { | ||
140 | break; | ||
141 | } | ||
142 | |||
143 | array[arrayIndex++] = tagsArray[i]; | ||
144 | } | ||
145 | |||
146 | if (found) | ||
147 | { | ||
148 | this.tags = array; | ||
149 | return true; | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | |||
154 | return false; | ||
155 | } | ||
156 | |||
157 | internal static IntermediateSymbol Deserialize(ISymbolDefinitionCreator creator, Uri baseUri, JsonObject jsonObject) | ||
158 | { | ||
159 | var definitionName = jsonObject.GetValueOrDefault<string>("type"); | ||
160 | var idJson = jsonObject.GetValueOrDefault<JsonObject>("id"); | ||
161 | var sourceLineNumbersJson = jsonObject.GetValueOrDefault<JsonObject>("ln"); | ||
162 | var fieldsJson = jsonObject.GetValueOrDefault<JsonArray>("fields"); | ||
163 | var tagsJson = jsonObject.GetValueOrDefault<JsonArray>("tags"); | ||
164 | |||
165 | var id = (idJson == null) ? null : Identifier.Deserialize(idJson); | ||
166 | var sourceLineNumbers = (sourceLineNumbersJson == null) ? null : SourceLineNumber.Deserialize(sourceLineNumbersJson); | ||
167 | |||
168 | // TODO: this isn't sufficient. | ||
169 | if (!creator.TryGetSymbolDefinitionByName(definitionName, out var definition)) | ||
170 | { | ||
171 | throw new WixException(ErrorMessages.UnknownSymbolType(definitionName)); | ||
172 | } | ||
173 | |||
174 | var symbol = definition.CreateSymbol(sourceLineNumbers, id); | ||
175 | |||
176 | for (var i = 0; i < fieldsJson.Count && i < symbol.Fields.Length; ++i) | ||
177 | { | ||
178 | if (fieldsJson[i] is JsonObject fieldJson) | ||
179 | { | ||
180 | symbol.Fields[i] = IntermediateField.Deserialize(symbol.Definition.FieldDefinitions[i], baseUri, fieldJson); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | if (tagsJson == null || tagsJson.Count == 0) | ||
185 | { | ||
186 | } | ||
187 | else if (tagsJson.Count == 1) | ||
188 | { | ||
189 | symbol.tags = (string)tagsJson[0]; | ||
190 | } | ||
191 | else | ||
192 | { | ||
193 | var tags = new string[tagsJson.Count]; | ||
194 | |||
195 | for (var i = 0; i < tagsJson.Count; ++i) | ||
196 | { | ||
197 | tags[i] = (string)tagsJson[i]; | ||
198 | } | ||
199 | |||
200 | symbol.tags = tags; | ||
201 | } | ||
202 | |||
203 | return symbol; | ||
204 | } | ||
205 | |||
206 | internal JsonObject Serialize() | ||
207 | { | ||
208 | var jsonObject = new JsonObject | ||
209 | { | ||
210 | { "type", this.Definition.Name } | ||
211 | }; | ||
212 | |||
213 | var idJson = this.Id?.Serialize(); | ||
214 | if (idJson != null) | ||
215 | { | ||
216 | jsonObject.Add("id", idJson); | ||
217 | } | ||
218 | |||
219 | var lnJson = this.SourceLineNumbers?.Serialize(); | ||
220 | if (lnJson != null) | ||
221 | { | ||
222 | jsonObject.Add("ln", lnJson); | ||
223 | } | ||
224 | |||
225 | var fieldsJson = new JsonArray(this.Fields.Length); | ||
226 | |||
227 | foreach (var field in this.Fields) | ||
228 | { | ||
229 | var fieldJson = field?.Serialize(); | ||
230 | fieldsJson.Add(fieldJson); | ||
231 | } | ||
232 | |||
233 | jsonObject.Add("fields", fieldsJson); | ||
234 | |||
235 | if (this.tags is string || this.tags is string[]) | ||
236 | { | ||
237 | JsonArray tagsJson; | ||
238 | |||
239 | if (this.tags is string tag) | ||
240 | { | ||
241 | tagsJson = new JsonArray(1) { tag }; | ||
242 | } | ||
243 | else | ||
244 | { | ||
245 | var array = (string[])this.tags; | ||
246 | tagsJson = new JsonArray(array.Length); | ||
247 | tagsJson.AddRange(array); | ||
248 | } | ||
249 | |||
250 | jsonObject.Add("tags", tagsJson); | ||
251 | } | ||
252 | |||
253 | return jsonObject; | ||
254 | } | ||
255 | } | ||
256 | } | ||