private void FindChildren(List <NodeEntry> nodes, NodeEntry node, int maxNextId) { if (node.ChildId > -1) { var nextId = node.NextId; if (nextId == -1) { nextId = maxNextId; } for (int i = node.ChildId; i < nextId; i++) { var possibleChild = nodes.FirstOrDefault(n => n.Id == i); if (possibleChild == null) { throw new Exception(); } if (possibleChild.ChildId > -1)//SubChild { FindChildren(nodes, possibleChild, nextId); node.AddChild(possibleChild); } else { if (!possibleChild.IsChild)//was already added { node.AddChild(possibleChild); } } } } }
private void ReadNodeInfos(BinaryReader reader) { var magicStartInt = BitConverter.ToUInt32(Encoding.ASCII.GetBytes(Constants.Magic.NODE_INFORMATION_START), 0); var magicEndInt = BitConverter.ToUInt32(Encoding.ASCII.GetBytes(Constants.Magic.END_OF_FILE), 0); reader.BaseStream.Seek(-8, SeekOrigin.End); var infoStart = reader.ReadInt32(); if (reader.ReadUInt32() != magicEndInt) { throw new Exception("invalid file format"); } reader.BaseStream.Seek(infoStart, SeekOrigin.Begin); if (reader.ReadUInt32() != magicStartInt) { throw new Exception("invalid file format"); } var length = reader.ReadPackedInt(); for (var i = 0; i < length; i++) { var name = reader.ReadPackedString(); var entry = new NodeEntry(); entry.NextId = reader.ReadInt32(); entry.ChildId = reader.ReadInt32(); entry.Offset = reader.ReadInt32(); entry.Size = reader.ReadInt32(); entry.Name = name; FlatNodes.Add(entry); } reader.BaseStream.Position = 0; }
public void LoadFromCompressedStream(Stream inputStream) { FlatNodes.Clear(); Nodes.Clear(); using (var reader = new BinaryReader(inputStream, Encoding.ASCII, true)) { string magic = reader.ReadString(4); Version1 = reader.ReadInt32(); Version2 = reader.ReadInt32(); SkippedHeaderBytes = reader.ReadBytes(9); Version3 = reader.ReadInt32(); int blockInfoStart = (int)reader.BaseStream.Position; reader.BaseStream.Seek(-8, SeekOrigin.End); LastBlockOffset = reader.ReadInt32(); reader.BaseStream.Seek(LastBlockOffset, SeekOrigin.Begin); string edonMagic = reader.ReadString(4); var flags = new Flags(reader); for (int i = 0; i < flags.Length; i++) { var tmpFlags = new Flags(reader.ReadByte()); string name = reader.ReadString(tmpFlags.Length); var entry = new NodeEntry(); entry.NextId = reader.ReadInt32(); entry.ChildId = reader.ReadInt32(); entry.Offset = reader.ReadInt32(); entry.Size = reader.ReadInt32(); entry.Name = name; FlatNodes.Add(entry); } } inputStream.Seek(0, SeekOrigin.Begin); var activeSaveFile = new SaveFileCompressionHelper(); var decompressedFile = activeSaveFile.Decompress(inputStream); using (MemoryStream memoryStream = new MemoryStream(decompressedFile)) { using (BinaryReader reader = new BinaryReader(memoryStream, Encoding.ASCII)) { foreach (var node in FlatNodes) { reader.BaseStream.Position = node.Offset; node.Id = reader.ReadInt32(); } foreach (var node in FlatNodes) { if (!node.IsChild) { FindChildren(FlatNodes, node, FlatNodes.Count); } if (node.NextId > -1) { node.SetNextNode(FlatNodes.Where(n => n.Id == node.NextId).FirstOrDefault()); } } Nodes.AddRange(FlatNodes.Where(n => !n.IsChild)); CalculateTrueSizes(); ParserUtils.ParseChildren(Nodes, reader, _parsers); } } }
public void AddChild(NodeEntry child) { child.IsChild = true; if (Children.Count == 0) { child.IsFirstChild = true; } Children.Add(child); child.SetParent(this); }
public void Write(NodeEntry node) { var isChild = _currentDepth > _lastDepth; var isNext = _currentDepth == _lastDepth; var isParent = _currentDepth < _lastDepth; _lastDepth = _currentDepth; _currentDepth++; var currentId = _currentId++; var nodeInfo = new SaveFile.NodeInfo { Name = node.Name, Offset = (int)BaseStream.Position }; if (isChild) { _nodeInfos[_nodeInfos.Count - 1].ChildId = currentId; } if (_nodeInfos.Count > 0 && isNext) { _nodeInfos[_nodeInfos.Count - 1].ChildId = -1; _nodeInfos[_nodeInfos.Count - 1].NextId = currentId; } if (isParent) { _nodeInfos[_nodeInfos.Count - 1].ChildId = -1; _nodeInfos[_nodeInfos.Count - 1].NextId = -1; var lastIdSameLevel = _nodeMetaInfos.LastOrDefault(n => n.Depth == _currentDepth).Id; _nodeInfos[lastIdSameLevel].NextId = currentId; } _nodeInfos.Add(nodeInfo); _nodeMetaInfos.Add(new NodeMeta(currentId, _currentDepth)); var parser = GetParser(node); Write(currentId); parser.Write(this, node); nodeInfo.Size = (int)(BaseStream.Position - nodeInfo.Offset); if (node.WritesOwnTrailingSize) { nodeInfo.Size -= node.TrailingSize; } _currentDepth--; }
private void CalculateTrueSizes(IReadOnlyList <NodeEntry> nodes, int maxLength) { for (var i = 0; i < nodes.Count; ++i) { var currentNode = nodes[i]; var nextNode = i + 1 < nodes.Count ? nodes[i + 1] : null; if (currentNode.Children.Count > 0) { // Check if there is a blob before the first child var nextChild = currentNode.Children.First(); var blobSize = nextChild.Offset - currentNode.Offset; currentNode.DataSize = blobSize; CalculateTrueSizes(currentNode.Children, maxLength); } else { currentNode.DataSize = currentNode.Size; } if (nextNode != null) { // There is a node after us. Check if there is a blob in between var blobSize = nextNode.Offset - (currentNode.Offset + currentNode.Size); if (blobSize < 0) { throw new InvalidDataException("Found a datablob with negative size"); } currentNode.TrailingSize = blobSize; } else { // There might be a blob that is part of the children due to the parents size, check for that if (currentNode.GetParent() == null) { // This is the last node on the root list. Trailing data should have been cought by the last inner child and assigned here but check again. var lastNodeEnd = currentNode.Offset + currentNode.Size; Debug.Assert(lastNodeEnd <= maxLength); if (lastNodeEnd < maxLength) { // There is a trailing blob currentNode.TrailingSize = maxLength - lastNodeEnd; } continue; } nextNode = currentNode.GetParent().GetNextNode(); if (nextNode == null) { // This is the last child on the last node. The next valid offset would be the end of the data // Create a virtual node for this so the code below can grab the offset nextNode = new NodeEntry(); nextNode.Offset = maxLength; } var parentMax = currentNode.GetParent().Offset + currentNode.GetParent().Size; var childMax = currentNode.Offset + currentNode.Size; // The parent size should never be smaller than the end of the last child. Debug.Assert(parentMax >= childMax); var blobSize = nextNode.Offset - (currentNode.Offset + currentNode.Size); if (blobSize < 0) { throw new InvalidDataException("Found a datablob with negative size"); } if (parentMax > childMax) { // Blob belongs to this child currentNode.TrailingSize = blobSize; } else if (parentMax == childMax) { // Blob belongs to the parent but as trailing. currentNode.GetParent().TrailingSize = blobSize; } } } }
private INodeParser GetParser(NodeEntry node) { return(GetParser(node.Name)); }
public void SetParent(NodeEntry parent) { _parent = parent; }
public void SetPreviousNode(NodeEntry previousNode) { _previousNode = previousNode; }
public void SetNextNode(NodeEntry nextNode) { _nextNode = nextNode; _nextNode.SetPreviousNode(this); }