NTP Analyzer  0.8.2
Analyze the operation of time servers
Decompiler.cs
Go to the documentation of this file.
1 //
2 // Copyright (c) 2013-2017 Carsten Sonne Larsen <cs@innolan.net>
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 
22 using System;
23 using System.Collections;
24 using System.Linq;
25 using System.Reflection;
26 using System.Text;
28 using Ntp.Analyzer.Config.Node;
29 using Ntp.Analyzer.Config.Table;
30 using Ntp.Analyzer.Interface;
31 
32 namespace Ntp.Analyzer.Config.Compiler
33 {
34  public sealed class Decompiler
35  {
39  public Decompiler()
40  {
41  IndentChar = ' ';
42  IndentSize = 8;
43  }
44 
45  private StringBuilder builder;
46 
51  public Configuration Configuration { get; set; }
52 
58  public bool ShowDefaultValues { get; set; }
59 
64  public char IndentChar { get; set; }
65 
70  public int IndentSize { get; set; }
71 
76  public string Execute()
77  {
78  builder = new StringBuilder();
79  DecompileConfiguration(-1, null, Configuration);
80  return builder.ToString();
81  }
82 
83  private void AppendDateTimeKind(DateTimeKind value)
84  {
85  switch (value)
86  {
87  case DateTimeKind.Local:
88  builder.Append(Keyword.Find(Symbol.KeywordTimeStampLocal).Name);
89  break;
90  case DateTimeKind.Utc:
91  case DateTimeKind.Unspecified:
92  builder.Append(Keyword.Find(Symbol.KeywordTimeStampUtc).Name);
93  break;
94  default:
95  builder.Append(Keyword.Find(Symbol.KeywordTimeStampUtc).Name);
96  break;
97  }
98  }
99 
104  private void AppendIndent(int size)
105  {
106  builder.Append(string.Empty.PadLeft(size*IndentSize, IndentChar));
107  }
108 
115  private void AppendString(string value, Layout layout, int indent)
116  {
117  switch (layout)
118  {
119  case Layout.Block:
120  builder.AppendLine("{ ");
121  var lines = value.Trim().Split(
122  new[] {Environment.NewLine},
123  StringSplitOptions.None
124  );
125  foreach (var line in lines)
126  {
127  AppendIndent(indent + 1);
128  builder.AppendLine(line.Trim());
129  }
130  AppendIndent(indent);
131  builder.Append("}");
132  break;
133  case Layout.Quoted:
134  builder.Append("\"");
135  builder.Append(value);
136  builder.Append("\"");
137  break;
138  case Layout.Normal:
139  if (value.Contains(" ") || value.Contains("\t"))
140  {
141  builder.Append("\"");
142  builder.Append(value);
143  builder.Append("\"");
144  }
145  else
146  {
147  builder.Append(value);
148  }
149  break;
150  default:
151  builder.Append(value);
152  break;
153  }
154  }
155 
161  private void DecompileComplexType(int indent, object node)
162  {
163  var properties = node.GetType().GetProperties().
164  OrderBy(
165  delegate(PropertyInfo info)
166  {
167  var attribute = System.Attribute.GetCustomAttribute(info, typeof(NtpaIndex));
168  return ((NtpaIndex) attribute)?.Index ?? int.MaxValue;
169  });
170 
171  foreach (var property in properties)
172  {
173  if (DecompileSetting(indent, node, property))
174  continue;
175 
176  if (DecompileSettingCollection(indent, node, property))
177  continue;
178 
179  if (DecompileReferenceCollection(indent, node, property))
180  continue;
181 
182  DecompileReference(indent, node, property);
183  }
184  }
185 
192  private void DecompileConfiguration(int indent, string typeName, IConfigurationNode node)
193  {
194  if (node == null)
195  return;
196 
197  // Swap builders
198  var temp = builder;
199  builder = new StringBuilder();
200 
201  DecompileComplexType(indent + 1, node);
202 
203  // Swap builder back
204  var res = builder;
205  builder = temp;
206 
207  // Skip empty nodes
208  if (res.ToString().Trim() == string.Empty)
209  return;
210 
211  if (indent >= 0)
212  {
213  // Make a blank line
214  AppendIndent(indent);
215  builder.AppendLine();
216 
217  // Write header
218  AppendIndent(indent);
219  builder.Append(typeName);
220 
221  if (node.ConfigName != null)
222  {
223  builder.Append(" ");
224  builder.Append(node.ConfigName);
225  }
226 
227  builder.AppendLine(" {");
228  }
229 
230  builder.Append(res);
231 
232  if (indent >= 0)
233  {
234  AppendIndent(indent);
235  builder.AppendLine("}");
236  }
237  }
238 
245  private void DecompileReference(int indent, object node, PropertyInfo property)
246  {
247  var reference = (NtpaReference) System.Attribute.GetCustomAttribute(property, typeof(NtpaReference));
248  if (reference == null)
249  return;
250 
251  var value = property.GetValue(node, null);
252  if (value == null)
253  return;
254 
255  var keyword = Keyword.Find(reference.Keyword);
256  var configurationNode = value as IConfigurationNode;
257  if (configurationNode == null)
258  return;
259 
260  var name = configurationNode.ConfigName;
261  DecompileSimpleType(indent, keyword.Name, name, null, Layout.Normal);
262  }
263 
271  private bool DecompileReferenceCollection(int indent, object node, PropertyInfo property)
272  {
273  var attribute = System.Attribute.GetCustomAttribute(property, typeof(NtpaReferenceCollection));
274  if (attribute == null)
275  return false;
276 
277  var refCollection = (NtpaReferenceCollection) attribute;
278 
279  var value = property.GetValue(node, null);
280  if (!(value is IEnumerable))
281  return true;
282 
283  var keyword = Keyword.Find(refCollection.Keyword);
284  foreach (var subObject in value as IEnumerable)
285  {
286  var configurationNode = subObject as IConfigurationNode;
287  if (configurationNode != null)
288  {
289  var name = configurationNode.ConfigName;
290  DecompileSimpleType(indent, keyword.Name, name, null, Layout.Normal);
291  }
292  }
293 
294  return true;
295  }
296 
304  private bool DecompileSetting(int indent, object node, PropertyInfo property)
305  {
306  var setting = (NtpaSetting) System.Attribute.GetCustomAttribute(property, typeof(NtpaSetting));
307  if (setting == null)
308  return false;
309 
310  var keyword = Keyword.Find(setting.Keyword);
311  var value = property.GetValue(node, null);
312  if (value == null)
313  return true;
314 
315  if (value is IConfigurationNode)
316  {
317  DecompileConfiguration(indent, keyword.Name, value as IConfigurationNode);
318  }
319  else
320  {
321  DecompileSimpleType(indent, keyword.Name, value, setting.Value, setting.Layout);
322  }
323 
324  return true;
325  }
326 
334  private bool DecompileSettingCollection(int indent, object node, PropertyInfo property)
335  {
336  var attribute = System.Attribute.GetCustomAttribute(property, typeof(NtpaSettingsCollection));
337  if (attribute == null)
338  return false;
339 
340  var collection = (NtpaSettingsCollection) attribute;
341 
342  var value = property.GetValue(node, null);
343  if (value == null)
344  return true;
345 
346  // Decompile the collection in flat style
347  if (collection.Flatten && value is IEnumerable)
348  {
349  foreach (var subObject in value as IEnumerable)
350  {
351  DecompileComplexType(indent, subObject);
352  }
353  return true;
354  }
355 
356  if (!(value is IEnumerable))
357  return true;
358 
359  var raiseAdd = 0;
360  if (collection.Raise != Symbol.Undefined)
361  {
362  var raise = Keyword.Find(collection.Raise);
363  AppendIndent(indent);
364  builder.Append(raise.Name);
365  builder.AppendLine(" {");
366  raiseAdd = 1;
367  }
368 
369  var keyword = Keyword.Find(collection.Keyword);
370  foreach (var subObject in value as IEnumerable)
371  {
372  DecompileConfiguration(indent + raiseAdd, keyword.Name, subObject as IConfigurationNode);
373  }
374 
375  if (collection.Raise != Symbol.Undefined)
376  {
377  AppendIndent(indent);
378  builder.AppendLine("}");
379  }
380 
381  return true;
382  }
383 
392  private void DecompileSimpleType(int indent, string name, object value, object defaultValue, Layout layout)
393  {
394  if (!ShowDefaultValues && value.Equals(defaultValue))
395  return;
396 
397  if (layout == Layout.Block)
398  {
399  AppendIndent(indent);
400  builder.AppendLine();
401  }
402 
403  AppendIndent(indent);
404  builder.Append(name);
405  builder.Append(" ");
406 
407  if (value is bool)
408  {
409  builder.Append((bool) value ? "Yes" : "No");
410  }
411  else if (value is string)
412  {
413  AppendString((string) value, layout, indent);
414  }
415  else if (value is DateTimeKind)
416  {
417  AppendDateTimeKind((DateTimeKind) value);
418  }
419  else if (value is Uri)
420  {
421  AppendString(((Uri) value).OriginalString, layout, indent);
422  }
423  else
424  {
425  builder.Append(value);
426  }
427 
428  builder.AppendLine();
429  }
430  }
431 }
void AppendDateTimeKind(DateTimeKind value)
Definition: Decompiler.cs:83
bool DecompileReferenceCollection(int indent, object node, PropertyInfo property)
Decompiles a property with a collection of references if applicable.
Definition: Decompiler.cs:271
bool DecompileSettingCollection(int indent, object node, PropertyInfo property)
Decompiles a collection property if applicable.
Definition: Decompiler.cs:334
void DecompileComplexType(int indent, object node)
Decompiles a complex node type (classes).
Definition: Decompiler.cs:161
void DecompileConfiguration(int indent, string typeName, IConfigurationNode node)
Decompiles a configuration section.
Definition: Decompiler.cs:192
void AppendString(string value, Layout layout, int indent)
Appends the string to output.
Definition: Decompiler.cs:115
static Keyword Find(Symbol symbol)
Definition: Keyword.cs:216
Decompiler()
Initializes a new instance of the Decompiler class.
Definition: Decompiler.cs:39
void DecompileReference(int indent, object node, PropertyInfo property)
Decompiles a reference property if applicable.
Definition: Decompiler.cs:245
bool DecompileSetting(int indent, object node, PropertyInfo property)
Decompiles a setting property if applicable.
Definition: Decompiler.cs:304
string Execute()
Execute the decompiler.
Definition: Decompiler.cs:76
void DecompileSimpleType(int indent, string name, object value, object defaultValue, Layout layout)
Decompiles a simple node type (integers, strings, etc.)
Definition: Decompiler.cs:392
void AppendIndent(int size)
Appends indent to output.
Definition: Decompiler.cs:104