/// <summary> /// Initializes a new instance of the <see cref="XmlReader"/> class. /// </summary> /// <param name="buffer">An array of bytes containing the contents of a binary XML.</param> public XmlReader(byte[] buffer) { //Read header section. var binaryBuffer = new BigEndianBinaryBuffer(buffer); var signature = binaryBuffer.ReadU8(); var compressionFlag = binaryBuffer.ReadU8(); var encodingFlag = binaryBuffer.ReadU8(); var encodingFlagNot = binaryBuffer.ReadU8(); //Verify magic. if (signature != 0xA0) { throw new KbinException($"Signature was invalid. {signature} != 0xA0"); } //Encoding flag should be an inverse of the fourth byte. if ((byte)~encodingFlag != encodingFlagNot) { throw new KbinException($"Third byte was not an inverse of the fourth. {~encodingFlag} != {encodingFlagNot}"); } var compressed = compressionFlag == 0x42; var encoding = EncodingDictionary.EncodingMap[encodingFlag]; //Get buffer lengths and load. var nodeLength = binaryBuffer.ReadS32(); _nodeBuffer = new NodeBuffer(buffer.Skip(8).Take(nodeLength).ToArray(), compressed, encoding); var dataLength = BitConverter.ToInt32(buffer.Skip(nodeLength + 8).Take(4).Reverse().ToArray(), 0); _dataBuffer = new DataBuffer(buffer.Skip(nodeLength + 12).Take(dataLength).ToArray(), encoding); _xmlDocument.InsertBefore(_xmlDocument.CreateXmlDeclaration("1.0", encoding.WebName, null), _xmlDocument.DocumentElement); }
/// <summary> /// Writes all nodes in the XML document. /// </summary> /// <returns>Retruns an array of bytes containing the contents of the binary XML.</returns> public byte[] Write() { Recurse(_xmlDocument.DocumentElement); _nodeBuffer.WriteU8(255); _nodeBuffer.Pad(); _dataBuffer.Pad(); //Write header data var output = new BigEndianBinaryBuffer(); output.WriteU8(0xA0); //Magic output.WriteU8(0x42); //Compression flag output.WriteU8(EncodingDictionary.ReverseEncodingMap[_encoding]); output.WriteU8((byte)~EncodingDictionary.ReverseEncodingMap[_encoding]); //Write node buffer length and contents. output.WriteS32(_nodeBuffer.ToArray().Length); output.WriteBytes(_nodeBuffer.ToArray()); //Write data buffer length and contents. output.WriteS32(_dataBuffer.ToArray().Length); output.WriteBytes(_dataBuffer.ToArray()); return(output.ToArray()); }
private byte[] WriteXml() { XmlRecurse(_document.Root); _nodeBuffer.WriteU8(255); _nodeBuffer.Pad(); _dataBuffer.Pad(); //Write header data using (var output = new BigEndianBinaryBuffer()) { output.WriteU8(0xA0); //Magic output.WriteU8(0x42); //Compression flag output.WriteU8(EncodingDictionary.ReverseEncodingMap[_encoding]); output.WriteU8((byte)~EncodingDictionary.ReverseEncodingMap[_encoding]); //Write node buffer length and contents. var buffer = _nodeBuffer.ToArray(); output.WriteS32(buffer.Length); output.WriteBytes(buffer); //Write data buffer length and contents. var array = _dataBuffer.ToArray(); output.WriteS32(array.Length); output.WriteBytes(array); return(output.ToArray()); } }
/// <summary> /// Initializes a new instance of the <see cref="KbinReader"/> class. /// </summary> /// <param name="buffer">An array of bytes containing the contents of a binary XML.</param> public KbinReader(byte[] buffer) { //Read header section. var binaryBuffer = new BigEndianBinaryBuffer(buffer); var signature = binaryBuffer.ReadU8(); var compressionFlag = binaryBuffer.ReadU8(); var encodingFlag = binaryBuffer.ReadU8(); var encodingFlagNot = binaryBuffer.ReadU8(); //Verify magic. if (signature != 0xA0) { throw new KbinException($"Signature was invalid. 0x{signature.ToString("X2")} != 0xA0"); } //Encoding flag should be an inverse of the fourth byte. if ((byte)~encodingFlag != encodingFlagNot) { throw new KbinException($"Third byte was not an inverse of the fourth. {~encodingFlag} != {encodingFlagNot}"); } var compressed = compressionFlag == 0x42; Encoding = EncodingDictionary.EncodingMap[encodingFlag]; //Get buffer lengths and load. var span = new Span <byte>(buffer); var nodeLength = binaryBuffer.ReadS32(); _nodeBuffer = new NodeBuffer(span.Slice(8, nodeLength).ToArray(), compressed, Encoding); var dataLength = BitConverterHelper.GetBigEndianInt32(span.Slice(nodeLength + 8, 4)); _dataBuffer = new DataBuffer(span.Slice(nodeLength + 12, dataLength).ToArray(), Encoding); var settings = new XmlWriterSettings { Async = false, Encoding = Encoding, Indent = false }; _writerStream = new MemoryStream(); _xmlWriter = XmlWriter.Create(_writerStream, settings); _xmlWriter.WriteStartDocument(); }
private byte[] WriteRaw() { using (var textReader = new StringReader(_rawXml)) using (var reader = XmlReader.Create(textReader, new XmlReaderSettings { IgnoreWhitespace = true })) { var holdingAttrs = new SortedDictionary <string, string>(StringComparer.Ordinal); string holdingValue = ""; string typeStr = null, sizeStr = null; byte typeid = 0; void EnsureHolding() { if (typeStr != null) { if (typeStr == "str") { _dataBuffer.WriteString(holdingValue); } else if (typeStr == "bin") { _dataBuffer.WriteBinary(holdingValue); } else { var type = TypeDictionary.TypeMap[typeid]; var value = holdingValue.SpanSplit(' '); var size = (uint)(type.Size * type.Count); if (sizeStr != null) { size *= uint.Parse(sizeStr); _dataBuffer.WriteU32(size); } var arr = new byte[size]; int i = 0; foreach (var s in value) { if (i == arr.Length) { break; } #if NETSTANDARD2_1 || NET5_0_OR_GREATER var buffer = type.GetBytes(s); buffer.CopyTo(arr.AsSpan().Slice(i, type.Size)); #elif NETSTANDARD2_0 var buffer = type.GetBytes(s).ToArray(); buffer.CopyTo(arr, i); #endif i += type.Size; } _dataBuffer.WriteBytes(arr); } typeStr = null; sizeStr = null; holdingValue = ""; typeid = 0; } if (holdingAttrs.Count > 0) { foreach (var attribute in holdingAttrs) { _nodeBuffer.WriteU8(0x2E); _nodeBuffer.WriteString(attribute.Key); _dataBuffer.WriteString(attribute.Value); } holdingAttrs.Clear(); } } while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: EnsureHolding(); //Console.WriteLine("Start Element {0}", reader.Name); if (reader.AttributeCount > 0) { for (int i = 0; i < reader.AttributeCount; i++) { reader.MoveToAttribute(i); if (reader.Name == "__type") { typeStr = reader.Value; } else if (reader.Name == "__count") { sizeStr = reader.Value; } else { holdingAttrs.Add(reader.Name, reader.Value); } } reader.MoveToElement(); } if (typeStr == null) { _nodeBuffer.WriteU8(1); _nodeBuffer.WriteString(reader.Name); } else { typeid = TypeDictionary.ReverseTypeMap[typeStr]; if (sizeStr != null) { _nodeBuffer.WriteU8((byte)(typeid | 0x40)); } else { _nodeBuffer.WriteU8(typeid); } _nodeBuffer.WriteString(reader.Name); } if (reader.IsEmptyElement) { EnsureHolding(); _nodeBuffer.WriteU8(0xFE); } break; case XmlNodeType.Text: holdingValue = reader.Value; break; case XmlNodeType.EndElement: EnsureHolding(); _nodeBuffer.WriteU8(0xFE); break; default: //Console.WriteLine("Other node {0} with value {1}", // reader.NodeType, reader.Value); break; } } EnsureHolding(); } _nodeBuffer.WriteU8(255); _nodeBuffer.Pad(); _dataBuffer.Pad(); //Write header data using (var output = new BigEndianBinaryBuffer()) { output.WriteU8(0xA0); //Magic output.WriteU8(0x42); //Compression flag output.WriteU8(EncodingDictionary.ReverseEncodingMap[_encoding]); output.WriteU8((byte)~EncodingDictionary.ReverseEncodingMap[_encoding]); //Write node buffer length and contents. var buffer = _nodeBuffer.ToArray(); output.WriteS32(buffer.Length); output.WriteBytes(buffer); //Write data buffer length and contents. var array = _dataBuffer.ToArray(); output.WriteS32(array.Length); output.WriteBytes(array); return(output.ToArray()); } }