/// <summary> /// Decode a node from the UTF file. /// </summary> /// <param name="buf">The byte array from the file.</param> /// <param name="nodeBlockStart">The offset in bytes to the start of the node block in buf</param> /// <param name="nodeStart">The offset to the current parent node in the node block</param> /// <param name="stringBlockOffset">The offset in bytes to the start of the string block in buf</param> /// <param name="dataBlockOffset">The offset in bytes to the start of the data block in buf</param> /// <param name="parent">The parent TreeNode</param> private void ParseNode(byte[] buf, int nodeBlockStart, int nodeStart, int stringBlockOffset, int dataBlockOffset, TreeNode parent) { int offset = nodeBlockStart + nodeStart; while (true) { int nodeOffset = offset; int peerOffset = Utilities.GetInt(buf, ref offset); // next node on same level int nameOffset = Utilities.GetInt(buf, ref offset); // string for this node int flags = Utilities.GetInt(buf, ref offset); // bit 4 set = intermediate, bit 7 set = leaf int zero = Utilities.GetInt(buf, ref offset); // always seems to be zero int childOffset = Utilities.GetInt(buf, ref offset); // next node in if intermediate, offset to data if leaf int allocatedSize = Utilities.GetInt(buf, ref offset); // leaf node only, 0 for intermediate int size = Utilities.GetInt(buf, ref offset); // leaf node only, 0 for intermediate int size2 = Utilities.GetInt(buf, ref offset); // leaf node only, 0 for intermediate int u1 = Utilities.GetInt(buf, ref offset); // timestamps. can be zero int u2 = Utilities.GetInt(buf, ref offset); int u3 = Utilities.GetInt(buf, ref offset); // Extract the node name int len = 0; // TODO: that's mad bro. // ReSharper disable once EmptyEmbeddedStatement for (int i = stringBlockOffset + nameOffset; i < buf.Length && buf[i] != 0; i++, len++) { ; } string name = Encoding.ASCII.GetString(buf, stringBlockOffset + nameOffset, len); // Extract data if this is a leaf. byte[] data; if ((flags & 0xFF) == 0x80) { if (size != size2) { MessageBox.Show(@"Possible compression being used on " + name, @"Warning"); } data = new byte[size]; Buffer.BlockCopy(buf, childOffset + dataBlockOffset, data, 0, size); } else { data = new byte[0]; } var node = new TreeNode { Data = data, Name = name }; parent.Add(name, node); if (childOffset > 0 && flags == 0x10) { ParseNode(buf, nodeBlockStart, childOffset, stringBlockOffset, dataBlockOffset, node); } if (Utilities.StrIEq(parent.Name, "Fixed", "Revolute")) { //TODO: test //Hardpoints.Nodes.Add(name, name); Hardpoints.Add(name, new TreeNode { Name = name }); } else if (Utilities.StrIEq(name, "Fix", "Trans", "Loose")) { AddParts(0xB0, data); } else if (Utilities.StrIEq(name, "Pris", "Rev")) { AddParts(0xD0, data); } else if (Utilities.StrIEq(name, "Sphere")) { AddParts(0xD4, data); } if (peerOffset == 0) { break; } offset = nodeBlockStart + peerOffset; } }