using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace Parsers { class DfmDataNode { public string PropertyName { get; set; } public string PropertyType { get; set; } public string PropertyClass { get; set; } public object PropertyValue { get; set; } public DfmDataNode Parent { get; set; } private string key = null; public string Key { get { if (key == null) { var s = PropertyName; var p = Parent; while (p != null) { s = p.PropertyName + "." + s; p = p.Parent; } key = s; } return key; } } private int? identLevel = null; public int IdentLevel { get { if (identLevel == null) { var r = 0; var p = Parent; while (p != null) { r++; p = p.Parent; } identLevel = r; } return identLevel.GetValueOrDefault(); } } public override string ToString() { if (PropertyClass != null) { return PropertyType + "::" + PropertyClass; } return PropertyType; } } class DfmParser { public DfmParser(string fileName) { OnReadNode += delegate { }; OnReadNodeCount += delegate { }; this.FileName = fileName; this.Nodes = new List(); } public event EventHandler OnReadNode; public event EventHandler OnReadNodeCount; public string FileName { get; private set; } public List Nodes { get; private set; } public long NodeCount { get; private set; } public void ReadFile() { if (!File.Exists(FileName)) return; using (var fileStream = new FileStream(FileName, FileMode.Open)) { using (var fileReader = new StreamReader(fileStream)) { var fileContent = new List(); while (!fileReader.EndOfStream) { fileContent.Add(fileReader.ReadLine()); } NodeCount = fileContent.Count(s => { return s.Contains("object") || s.Contains("inherited") || s.Contains("item") || s.Contains(" = <"); }); NodeCount = fileContent.Count - NodeCount; OnReadNodeCount(this, EventArgs.Empty); var node = ReadObjectProperties(fileContent, null); ((List)Nodes).Add(node); } } } private DfmDataNode ReadObjectProperties(IEnumerable objectData, DfmDataNode parent) { var obj = "object"; var inh = "inherited"; var node = new DfmDataNode(); var s = objectData.ElementAt(0); var k1 = s.IndexOf(obj) + obj.Length; node.PropertyType = obj; if (k1 == obj.Length-1) { k1 = s.IndexOf(inh) + inh.Length; node.PropertyType = inh; } var k2 = s.IndexOf(":"); k2 = k2 > -1 ? k2 : k1+1; node.Parent = parent; node.PropertyName = s.Substring(k1+1, k2-k1-1).Trim(); node.PropertyClass = s.Substring(k2+1, s.Length-k2-1).Trim(); node.PropertyValue = node; var index = 0; var count = objectData.Count()-2; while (index < count) { index = ReadObjectProperty(index, objectData, node); } return node; } private static class ItemCounter { private static int current = 0; internal static int NextValue { get { return ++current; } } internal static void Reset() { current = 0; } } private DfmDataNode ReadItemsProperties(IEnumerable objectData, DfmDataNode parent) { var node = new DfmDataNode(); var s = objectData.ElementAt(0); var k = s.IndexOf("="); if (k > -1) { node.PropertyName = s.Substring(0, k-1).Trim(); node.PropertyType = "items"; ItemCounter.Reset(); } else { node.PropertyName = "item" + ItemCounter.NextValue; node.PropertyType = "item"; } node.PropertyValue = node; node.Parent = parent; var index = 0; var count = objectData.Count()-2; while (index < count) { index = ReadObjectProperty(index, objectData, node); } return node; } private int ReadObjectProperty(int startIndex, IEnumerable objectData, DfmDataNode parent) { objectData = objectData.Skip(1).Take(objectData.Count()-2); var s = objectData.ElementAt(startIndex); var endIndex = startIndex; DfmDataNode node = null; if (s.EndsWith(" item")) { var ident = s.Substring(0, s.IndexOf("item")); endIndex = objectData.Skip(startIndex).ToList().IndexOf(ident+"end")+startIndex; if (endIndex == startIndex-1) { endIndex = objectData.Skip(startIndex).ToList().IndexOf(ident+"end>")+startIndex; } node = ReadItemsProperties( objectData.Skip(startIndex) .Take(endIndex-startIndex+1), parent ); } else if (s.IndexOf("inherited") > -1) { var ident = s.Substring(0, s.IndexOf("inherited")); endIndex = objectData.Skip(startIndex).ToList().IndexOf(ident+"end")+startIndex; node = ReadObjectProperties( objectData.Skip(startIndex) .Take(endIndex-startIndex+1), parent ); } else if (s.IndexOf("object") > -1) { var ident = s.Substring(0, s.IndexOf("object")); endIndex = objectData.Skip(startIndex).ToList().IndexOf(ident+"end")+startIndex; node = ReadObjectProperties( objectData.Skip(startIndex) .Take(endIndex-startIndex+1), parent ); } else { var k = s.IndexOf("="); node = new DfmDataNode(); node.PropertyName = s.Substring(0, k-1).Trim(); node.Parent = parent; var b0 = (!s.StartsWith("'")) && (!s.StartsWith("#")); var b1 = s.EndsWith("= ("); var b2 = s.EndsWith("= {"); var b3 = s.EndsWith("= <"); if ((b0) && (b1 || b2 || b3)) { var endTerm1 = ")"; var endTerm2 = "}"; var endTerm3 = ">"; string endTerm = endTerm1; if (b2) endTerm = endTerm2; if (b3) endTerm = endTerm3; endIndex = objectData.ToList().IndexOf( objectData.First(o => { return o.EndsWith(endTerm) && !o.EndsWith("<>"); }) ); if (b1 || b2) { node.PropertyValue = new List(); if (b1) { node.PropertyType = "record"; ((List)node.PropertyValue).Add("("); } else { node.PropertyType = "binary"; ((List)node.PropertyValue).Add("{"); } ((List)node.PropertyValue).AddRange( objectData.Skip(startIndex+1).Take(endIndex-startIndex) ); } else { node = ReadItemsProperties( objectData.Skip(startIndex).Take(endIndex-startIndex+2), parent ); } } else { node.PropertyValue = s.Substring(k+1, s.Length-k-1).Trim(); if ((s.Contains("'")) || (s.Contains("#"))) { node.PropertyType = "string"; } else { var numbers = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; var v = node.PropertyValue.ToString(); var c = v.Substring(v.Length-1, 1); if (numbers.Contains(c)) { node.PropertyType = "number"; } else if ((node.PropertyType == "True") || (node.PropertyType == "False")) { node.PropertyType = "boolean"; } else { node.PropertyType = "unknown"; } } } } ((List)Nodes).Add(node); OnReadNode(this, EventArgs.Empty); return endIndex+1; } public void SaveFile() { var fileContent = new List(); WriteNodes(fileContent, 0, null); File.WriteAllLines(FileName, fileContent.ToArray(), Encoding.Unicode); } private void WriteNodes(List fileContent, int identLevel, DfmDataNode parentNode) { foreach (var node in Nodes) { if ((node.Parent == parentNode) && (node.IdentLevel == identLevel)) { WriteNode(node, fileContent, identLevel); } } } private void WriteNode(DfmDataNode node, List fileContent, int identLevel) { var iLevel = identLevel * 2; var space = " "; var equal = " = "; var colon = ": "; var less = "<"; var more = ">"; var end = "end"; var ident = String.Empty; for (int i = 0; i < iLevel; i++) { ident += space; } switch (node.PropertyType) { case "boolean": case "string": case "number": case "unknown": fileContent.Add(ident + node.PropertyName + equal + node.PropertyValue); break; case "record": case "binary": var list = node.PropertyValue as List; fileContent.Add(ident + node.PropertyName + equal + list[0]); list.Skip(1).All( s => { fileContent.Add(s); return true; } ); break; case "inherited": case "object": fileContent.Add(ident + node.PropertyType + space + node.PropertyName + colon + node.PropertyClass); WriteNodes(fileContent, ++identLevel, node); fileContent.Add(ident + end); break; case "items": fileContent.Add(ident + node.PropertyName + equal + less); WriteNodes(fileContent, ++identLevel, node); fileContent[fileContent.Count-1] = fileContent[fileContent.Count-1] + more; break; case "item": fileContent.Add(ident + node.PropertyType); WriteNodes(fileContent, ++identLevel, node); fileContent.Add(ident + end); break; } } } }