protected void ReadTypeTreeNode(DumpReader reader, int indent) { Type = ReadType(reader); Name = ReadName(reader); reader.FindValidateWord("//"); ByteSize = ReadHexIntParameter(reader, "ByteSize"); reader.FindValidateLineWord(","); Index = ReadHexIntParameter(reader, "Index"); reader.FindValidateLineWord(","); Version = ReadHexIntParameter(reader, "Version"); reader.FindValidateLineWord(","); IsArray = ReadBoolParameter(reader, "IsArray"); reader.FindValidateLineWord(","); MetaFlag = unchecked ((uint)ReadHexIntParameter(reader, "MetaFlag")); reader.FindValidateEOL(); reader.FindNextLine(); int childIndent = indent + 1; List <TreeNodeDump> children = new List <TreeNodeDump>(); while (reader.PeekIndend() == childIndent) { TreeNodeDump child = new TreeNodeDump(); child.ReadTypeTreeNode(reader, childIndent); children.Add(child); } Children = children.ToArray(); }
public virtual TreeNodeDump Optimize() { TreeNodeDump node = new TreeNodeDump(); Optimize(node); return(node); }
private TreeNodeDiff(TreeNodeDump node, bool left) { if (node == null) { throw new ArgumentNullException(nameof(node)); } Name = node.Name ?? throw new ArgumentNullException(nameof(node.Name)); string type = node.Type ?? throw new ArgumentNullException(nameof(node.Type)); LeftType = left ? string.Empty : type; RightType = left ? type : string.Empty; LeftVersion = left ? 0 : node.Version; RightVersion = left ? node.Version : 0; LeftAlign = left ? false : node.IsAlign; RightAlign = left ? node.IsAlign : false; TreeNodeDiff[] children = node.Children.Select(t => new TreeNodeDiff(t, left)).ToArray(); LeftChildren = left ? children : new TreeNodeDiff[0]; RightChildren = left ? new TreeNodeDiff[0] : children; Status = DeepStatus = DiffStatus.Changed; }
public TreeNodeDiff(TreeNodeDump node, DiffStatus status) { if (node == null) { throw new ArgumentNullException(nameof(node)); } if (status != DiffStatus.Added && status != DiffStatus.Deleted) { throw new ArgumentException(nameof(status)); } Name = node.Name ?? throw new ArgumentNullException(nameof(node.Name)); string type = node.Type ?? throw new ArgumentNullException(nameof(node.Type)); LeftType = status == DiffStatus.Added ? string.Empty : type; RightType = status == DiffStatus.Added ? type : string.Empty; LeftVersion = status == DiffStatus.Added ? 0 : node.Version; RightVersion = status == DiffStatus.Added ? node.Version : 0; LeftAlign = status == DiffStatus.Added ? false : node.IsAlign; RightAlign = status == DiffStatus.Added ? node.IsAlign : false; int childNodeCount = node.GetNodeCount() - 1; TreeNodeDiff emptyElement = childNodeCount == 0 ? null : new TreeNodeDiff(status); TreeNodeDiff[] children = node.Children.Select(t => new TreeNodeDiff(t, status)).ToArray(); TreeNodeDiff[] emptyChildren = Enumerable.Repeat(emptyElement, childNodeCount).ToArray(); LeftChildren = status == DiffStatus.Added ? emptyChildren : children; RightChildren = status == DiffStatus.Added ? children : emptyChildren; Status = DeepStatus = status; }
private static bool IsNodePresent(TreeNodeDump node, TreeNodeDump right, int startIndex) { for (int ri = startIndex + 1; ri < right.Children.Count; ri++) { TreeNodeDump rightChild = right.Children[ri]; if (IsNodeSame(node, rightChild)) { return(true); } } return(false); }
private static TreeNodeDiff[] CreateChildren(TreeNodeDump left, TreeNodeDump right) { List <TreeNodeDiff> children = new List <TreeNodeDiff>(); for (int li = 0, ri = 0; li < left.Children.Count || ri < right.Children.Count;) { if (li == left.Children.Count) { TreeNodeDiff node = new TreeNodeDiff(right.Children[ri], DiffStatus.Added); children.Add(node); ri++; continue; } if (ri == right.Children.Count) { TreeNodeDiff node = new TreeNodeDiff(left.Children[li], DiffStatus.Deleted); children.Add(node); li++; continue; } TreeNodeDump leftChild = left.Children[li]; TreeNodeDump rightChild = right.Children[ri]; if (IsNodeSame(leftChild, rightChild)) { TreeNodeDiff node = new TreeNodeDiff(leftChild, rightChild); children.Add(node); li++; ri++; continue; } if (IsNodePresent(leftChild, right, ri)) { do { TreeNodeDiff node = new TreeNodeDiff(rightChild, DiffStatus.Added); children.Add(node); ri++; rightChild = right.Children[ri]; } while (!IsNodeSame(leftChild, rightChild)); } else { TreeNodeDiff node = new TreeNodeDiff(leftChild, DiffStatus.Deleted); children.Add(node); li++; continue; } } return(children.ToArray()); }
private void CopyTypeTreeNode(TreeNodeDump node, int indent, StringBuilder sb) { sb.Append('\t', indent).Append(node.Type).Append(' ').Append(node.Name); // Nice bug, C#. Look at this beautiful piece of... code sb.AppendFormat(" // ByteSize{0}{1:x}{2}, Index{3}{4:x}{5}, Version{6}{7:x}{8}, IsArray{{{9}}}, MetaFlag{10}{11:x}{12}", "{", unchecked ((uint)node.ByteSize), "}", "{", node.Index, "}", "{", node.Version, "}", node.IsArray ? 1 : 0, "{", node.MetaFlag, "}").AppendLine(); foreach (TreeNodeDump child in node.Children) { CopyTypeTreeNode(child, indent + 1, sb); } }
private TreeNodeDiff(TreeNodeDump left, TreeNodeDump right, bool forceMerge) { if (left == null) { throw new ArgumentNullException(nameof(left)); } if (right == null) { throw new ArgumentNullException(nameof(right)); } if (left.Name != right.Name) { throw new ArgumentException("Left and right names aren't equal"); } Name = left.Name ?? throw new ArgumentNullException(nameof(left.Name)); LeftType = left.Type ?? throw new ArgumentNullException(nameof(left.Type)); RightType = right.Type ?? throw new ArgumentNullException(nameof(left.Type)); LeftVersion = left.Version; RightVersion = right.Version; LeftAlign = left.IsAlign; RightAlign = right.IsAlign; Status = (LeftType == RightType && LeftVersion == RightVersion && LeftAlign == RightAlign) ? DiffStatus.Unchanged : DiffStatus.Changed; if (LeftType == RightType || forceMerge) { TreeNodeDiff[] children = CreateChildren(left, right); LeftChildren = RightChildren = children; DeepStatus = children.All(t => t.DeepStatus == DiffStatus.Unchanged) ? Status : DiffStatus.Changed; } else { int leftNodeCount = left.GetNodeCount(); int rightNodeCount = right.GetNodeCount(); int extraLeft = Math.Max(rightNodeCount - leftNodeCount, 0); int extraRight = Math.Max(leftNodeCount - rightNodeCount, 0); TreeNodeDiff extraElement = leftNodeCount == rightNodeCount ? null : new TreeNodeDiff(DiffStatus.Changed); IEnumerable <TreeNodeDiff> extraLeftChildren = Enumerable.Repeat(extraElement, extraLeft); IEnumerable <TreeNodeDiff> extraRightChildren = Enumerable.Repeat(extraElement, extraRight); LeftChildren = left.Children.Select(t => new TreeNodeDiff(t, false)).Concat(extraLeftChildren).ToArray(); RightChildren = right.Children.Select(t => new TreeNodeDiff(t, true)).Concat(extraRightChildren).ToArray(); DeepStatus = DiffStatus.Changed; } }
protected void Optimize(TreeNodeDump dest) { string type = Type; dest.Type = ToOptimizedType(this); dest.Name = Name; dest.ByteSize = ByteSize; dest.Index = Index; dest.Version = Version; dest.IsArray = IsArray; dest.MetaFlag = MetaFlag; IReadOnlyList <TreeNodeDump> children = GetOptimizedChildren(); int childCount = children == null ? 0 : children.Count; TreeNodeDump[] newChildren = new TreeNodeDump[childCount]; for (int i = 0; i < childCount; i++) { newChildren[i] = children[i].Optimize(); } dest.Children = newChildren; }
private static string ToOptimizedType(TreeNodeDump node) { string type = node.Type; IReadOnlyList <TreeNodeDump> children = node.Children; switch (type) { case "SInt8": return("sbyte"); case "UInt8": return("byte"); case "SInt16": return("short"); case "UInt16": return("ushort"); case "SInt32": return("int"); case "UInt32": return("uint"); case "unsigned int": return("uint"); case "SInt64": return("long"); case "UInt64": return("ulong"); case "ColorRGBA": { if (children.Count == 1) { TreeNodeDump rgba = children[0]; if (ToOptimizedType(rgba) != "uint") { throw new Exception($"ColorRGBA's data node type {rgba.Name} doesn't match expected value 'unsigned int'"); } if (rgba.Name != "rgba") { throw new Exception($"ColorRGBA's data node name {rgba.Name} doesn't match expected value 'rgba'"); } return("ColorRGBA32"); } else if (children.Count == 4) { TreeNodeDump r = children[0]; TreeNodeDump g = children[1]; TreeNodeDump b = children[2]; TreeNodeDump a = children[3]; if (r.Type != "float") { throw new Exception($"ColorRGBA's R color node type {r.Name} doesn't match expected value 'float'"); } if (g.Type != "float") { throw new Exception($"ColorRGBA's G color node type {g.Name} doesn't match expected value 'float'"); } if (b.Type != "float") { throw new Exception($"ColorRGBA's B color node type {b.Name} doesn't match expected value 'float'"); } if (a.Type != "float") { throw new Exception($"ColorRGBA's A color node type {a.Name} doesn't match expected value 'float'"); } if (r.Name != "r") { throw new Exception($"ColorRGBA's R color node name {r.Name} doesn't match expected value 'r'"); } if (g.Name != "g") { throw new Exception($"ColorRGBA's R color node name {g.Name} doesn't match expected value 'g'"); } if (b.Name != "b") { throw new Exception($"ColorRGBA's R color node name {b.Name} doesn't match expected value 'b'"); } if (a.Name != "a") { throw new Exception($"ColorRGBA's R color node name {a.Name} doesn't match expected value 'a'"); } return("ColorRGBAf"); } else { throw new Exception($"ColorRGBA has {children.Count} children but expected 1 or 4"); } } case "vector": { if (children.Count != 1) { throw new Exception($"Vector has {children.Count} children but expected 1"); } TreeNodeDump array = children[0]; if (array.Children.Count != 2) { throw new Exception($"Vector's array node has {array.Children.Count} children but expected 2"); } if (array.Type != "Array") { throw new Exception($"Vector's array node type {array.Name} doesn't match expected value 'Array'"); } if (array.Name != "Array") { throw new Exception($"Vector's array node name {array.Name} doesn't match expected value 'Array'"); } TreeNodeDump vectorSize = array.Children[0]; if (ToOptimizedType(vectorSize) != "int") { throw new Exception($"Vector's size node type {vectorSize.Type} doesn't match expected value 'int'"); } if (vectorSize.Name != "size") { throw new Exception($"Vector's size node name {vectorSize.Name} doesn't match expected value 'size'"); } TreeNodeDump vectorValue = array.Children[1]; if (vectorValue.Name != "data") { throw new Exception($"Vector's value node name {vectorValue.Name} doesn't match expected value 'data'"); } return($"{ToOptimizedType(vectorValue)}[]"); } case "map": { if (children.Count != 1) { throw new Exception($"Map has {children.Count} children but expected 1"); } TreeNodeDump array = children[0]; if (array.Children.Count != 2) { throw new Exception($"Map's array node has {array.Children.Count} children but expected 2"); } if (array.Type != "Array") { throw new Exception($"Map's array node type {array.Name} doesn't match expected value 'Array'"); } if (array.Name != "Array") { throw new Exception($"Map's array node name {array.Name} doesn't match expected value 'Array'"); } TreeNodeDump mapSize = array.Children[0]; if (ToOptimizedType(mapSize) != "int") { throw new Exception($"Map's size node type {mapSize.Type} doesn't match expected value 'int'"); } if (mapSize.Name != "size") { throw new Exception($"Map's size node name {mapSize.Name} doesn't match expected value 'size'"); } TreeNodeDump pair = array.Children[1]; if (pair.Children.Count != 2) { throw new Exception($"Map's value node has {array.Children.Count} children but expected 2"); } if (pair.Type != "pair") { throw new Exception($"Map's value node type {pair.Type} doesn't match expected value 'pair'"); } if (pair.Name != "data") { throw new Exception($"Map's value node name {pair.Name} doesn't match expected value 'data'"); } TreeNodeDump key = pair.Children[0]; if (key.Name != "first") { throw new Exception($"Map's kvp-key node name {key.Name} doesn't match expected value 'first'"); } TreeNodeDump value = pair.Children[1]; if (value.Name != "second") { throw new Exception($"Map's kvp-value node name {value.Name} doesn't match expected value 'second'"); } return($"Dictionary<{ToOptimizedType(key)}, {ToOptimizedType(value)}>"); } case "set": { if (children.Count != 1) { throw new Exception($"Set has {children.Count} children but expected 1"); } TreeNodeDump array = children[0]; if (array.Children.Count != 2) { throw new Exception($"Set's array node has {array.Children.Count} children but expected 2"); } if (array.Type != "Array") { throw new Exception($"Set's array node type {array.Name} doesn't match expected value 'Array'"); } if (array.Name != "Array") { throw new Exception($"Set's array node name {array.Name} doesn't match expected value 'Array'"); } TreeNodeDump setSize = array.Children[0]; if (ToOptimizedType(setSize) != "int") { throw new Exception($"Set's size node type {setSize.Type} doesn't match expected value 'int'"); } if (setSize.Name != "size") { throw new Exception($"Set's size node name {setSize.Name} doesn't match expected value 'size'"); } TreeNodeDump setValue = array.Children[1]; if (setValue.Name != "data") { throw new Exception($"Set's value node name {setValue.Name} doesn't match expected value 'data'"); } return($"HashSet<{ToOptimizedType(setValue)}>"); } case "string": { if (children.Count != 1) { throw new Exception($"String has {children.Count} children but expected 1"); } TreeNodeDump array = children[0]; if (array.Children.Count != 2) { return(type); } if (array.Type != "Array") { throw new Exception($"String's array node type {array.Name} doesn't match expected value 'Array'"); } if (array.Name != "Array") { throw new Exception($"String's array node name {array.Name} doesn't match expected value 'Array'"); } TreeNodeDump stringSize = array.Children[0]; if (ToOptimizedType(stringSize) != "int") { throw new Exception($"String's size node type {stringSize.Type} doesn't match expected value 'int'"); } if (stringSize.Name != "size") { throw new Exception($"String's size node name {stringSize.Name} doesn't match expected value 'size'"); } TreeNodeDump stringValue = array.Children[1]; if (stringValue.Type != "char") { throw new Exception($"String's value node type {stringValue.Type} doesn't match expected value 'char'"); } if (stringValue.Name != "data") { throw new Exception($"String's value node name {stringValue.Name} doesn't match expected value 'data'"); } return("string"); } case "pair": { if (children.Count != 2) { throw new Exception($"Pair has {children.Count} children but expected 2"); } TreeNodeDump first = children[0]; if (first.Name != "first") { throw new Exception($"Pair's first child name {children[0].Name} doesn't match expected value 'first'"); } TreeNodeDump second = children[1]; if (second.Name != "second") { throw new Exception($"Pair's first child name {children[0].Name} doesn't match expected value 'second'"); } return($"KeyValuePair<{ToOptimizedType(first)}, {ToOptimizedType(second)}>"); } case "TypelessData": { if (children.Count != 2) { throw new Exception($"Typeless data has {children.Count} children but expected 2"); } TreeNodeDump dataSize = children[0]; if (ToOptimizedType(dataSize) != "int") { throw new Exception($"Typeless data's size node type {dataSize.Type} doesn't match expected value 'int'"); } if (dataSize.Name != "size") { throw new Exception($"Typeless data's size node name {dataSize.Name} doesn't match expected value 'size'"); } TreeNodeDump dataValue = children[1]; if (ToOptimizedType(dataValue) != "byte") { throw new Exception($"String's value node type {dataValue.Type} doesn't match expected value 'byte'"); } if (dataValue.Name != "data") { throw new Exception($"String's value node name {dataValue.Name} doesn't match expected value 'data'"); } return($"byte[]"); } default: return(type); } }
public TreeNodeDiff(TreeNodeDump left, TreeNodeDump right) : this(left, right, false) { }
private static bool IsNodeSame(TreeNodeDump left, TreeNodeDump right) { return(left.Name == right.Name); }