public Node?ReadNode() { if (NodeStream.Position >= NodeStream.Length) { return(null); } var(nodeType, isArray) = ReadNodeType(); var name = nodeType switch { NodeType.NodeEnd => "", NodeType.FileEnd => "", _ => _compression switch { Compression.Compressed => Sixbit.Unpack(NodeStream), Compression.Uncompressed => NodeStream.ReadString(NodeStream.ReadUInt8(), _encoding), _ => throw new ArgumentOutOfRangeException() } }; return(new Node(name, nodeType, isArray)); }
public KBinReader(byte[] data) { var document = new XDocument(); var node = document.Root; var nodeBuffer = new ByteBuffer(data); Assert(nodeBuffer.GetU8(), 0xA0); var compressedValue = nodeBuffer.GetU8(); if (compressedValue != 0x42 && compressedValue != 0x45) { throw new Exception(); } var compressed = compressedValue == 0x42; var encodingIndex = nodeBuffer.GetU8(); var encodingCheck = nodeBuffer.GetU8(); Assert(encodingCheck, (byte)(encodingIndex ^ 0xFF)); var encoding = Encodings[encodingIndex >> 5]; var nodeEnd = (int)nodeBuffer.GetU32() + 8; var dataBuffer = new ByteBuffer(data, nodeEnd); var dataSize = dataBuffer.GetU32(); var dataByteBuffer = new ByteBuffer(data, nodeEnd); var dataWordBuffer = new ByteBuffer(data, nodeEnd); document.Declaration = new XDeclaration("1.0", encoding.WebName, ""); var nodesLeft = true; while (nodesLeft) { while (nodeBuffer.PeekU8() == 0) { nodeBuffer.GetU8(); } var nodeType = nodeBuffer.GetU8(); var isArray = nodeType >> 6 == 1; nodeType &= 0b10111111; Formats.TryGetValue(nodeType, out var format); var name = ""; if (nodeType != (byte)Control.NodeEnd && nodeType != (byte)Control.SectionEnd) { if (compressed) { name = Sixbit.Decode(nodeBuffer); } else { var length = (nodeBuffer.GetU8() & 0b10111111) + 1; name = encoding.GetString(nodeBuffer.GetBytes(length)).Trim('\0'); } } var skip = true; if (nodeType == (byte)Control.Attribute) { var readDataAuto = ReadDataAuto(dataBuffer); Array.Reverse(readDataAuto); var value = encoding.GetString(readDataAuto).Trim('\0'); node?.SetAttributeValue(name, value); } else if (nodeType == (byte)Control.NodeEnd) { if (node?.Parent != null) { node = node.Parent; } } else if (nodeType == (byte)Control.SectionEnd) { nodesLeft = false; } else { skip = false; } if (skip) { continue; } var child = new XElement(name); node?.Add(child); node = child; if (nodeType == (byte)Control.NodeStart) { continue; } node.SetAttributeValue("__type", format.Name); var count = format.Count; var arrayCount = 1; if (count == -1) { count = (int)dataBuffer.GetU32(); isArray = true; } else if (isArray) { arrayCount = (int)(dataBuffer.GetU32() / (format.Size * count)); node.SetAttributeValue("__count", arrayCount); } var totalCount = arrayCount * count; byte[] nodeData; if (isArray) { nodeData = dataBuffer.GetBytes(totalCount); dataBuffer.RealignRead(); } else { nodeData = ReadDataAligned(dataBuffer, dataByteBuffer, dataWordBuffer, format.Size, format.Count); } var text = ""; if (format.Equals(Format.Binary)) { node.SetAttributeValue("__size", totalCount); Array.Reverse(nodeData); for (var i = 0; i < nodeData.Length; i++) { text += nodeData[i].ToString("x2"); } } else if (format.Equals(Format.String)) { Array.Reverse(nodeData); text = encoding.GetString(nodeData); } else if (isArray) { for (var i = 0; i < arrayCount; i++) { text = format.FormatToString(nodeData[(i * count)..((i + 1) * count)]) + " " + text;