using System.Text; using InnovEnergy.Lib.Protocols.DBus.Protocol.DataTypes; using InnovEnergy.Lib.Protocols.DBus.Protocol.DataTypes.Signatures; namespace InnovEnergy.Lib.Protocols.DBus.WireFormat; internal abstract class DBusReader { public Boolean SwapEndian { get; } public abstract Int32 BytesRead { get; } public abstract Byte ReadByte(); public abstract ArraySegment ReadSegment(Int32 size); // TODO protected DBusReader(Boolean swapEndian) => SwapEndian = swapEndian; public Int16 ReadInt16() { var span = ReadAlignedSpan(sizeof(Int16)); return BitConverter.ToInt16(span); } public UInt16 ReadUInt16() { var span = ReadAlignedSpan(sizeof(UInt16)); return BitConverter.ToUInt16(span); } public Int32 ReadInt32() { var span = ReadAlignedSpan(sizeof(Int32)); return BitConverter.ToInt32(span); } public UInt32 ReadUInt32() { var span = ReadAlignedSpan(sizeof(UInt32)); return BitConverter.ToUInt32(span); } public Int64 ReadInt64() { var span = ReadAlignedSpan(sizeof(Int64)); return BitConverter.ToInt64(span); } public UInt64 ReadUInt64() { var span = ReadAlignedSpan(sizeof(UInt64)); return BitConverter.ToUInt64(span); } public Boolean ReadBoolean() { var uInt32 = ReadUInt32(); return uInt32 switch { 0 => false, 1 => true, _ => throw new Exception($"Read value {uInt32} at position " + $"{BytesRead - sizeof(UInt32)} " + "while expecting boolean (0/1)") }; } public Double ReadDouble() { var span = ReadAlignedSpan(sizeof(Double)); return BitConverter.ToDouble(span); } public String ReadString() { var strLen = ReadInt32(); var span = ReadSegment(strLen); var str = Encoding.UTF8.GetString(span); SkipNull(); return str; } public ObjectPath ReadObjectPath() => ReadString(); public Signature ReadSignature() { var sigLen = ReadByte(); var span = ReadSegment(sigLen); var sig = Encoding.ASCII.GetString(span); // only ascii chars allowed in sig SkipNull(); return Signature.FromString(sig); } public Variant ReadVariant() { var signature = ReadSignature(); var value = signature.Read(this); return new Variant(value, signature); } public void AlignForComposite() => Align(8); // structs/arrays/dict elements are always 8-aligned private ReadOnlySpan ReadAlignedSpan(Int32 size) { Align(size); var start = BytesRead; var span = ReadSegment(size); if (SwapEndian) Array.Reverse(span.Array!, span.Offset + start, size); return span; } private void SkipNull() { if (ReadByte() != 0) throw new Exception("Read a non-zero byte while expecting a null byte"); } private void Align(Int32 alignment) { while (BytesRead % alignment != 0) SkipNull(); } public override String ToString() => $"@{BytesRead}"; } // internal abstract class DBusReader // { // public static Boolean Debug { get; set; } // public Boolean SwapEndian { get; } // // public abstract Int32 BytesRead { get; } // public abstract Byte ReadByte(); // public abstract ArraySegment ReadSegment(Int32 size); // TODO // // protected DBusReader(Boolean swapEndian) => SwapEndian = swapEndian; // // public Int16 ReadInt16() // { // var span = ReadAlignedSpan(sizeof(Int16)); // var r = BitConverter.ToInt16(span); // // if (Debug) Console.WriteLine("ReadInt16 " + r); // // return r; // } // // public UInt16 ReadUInt16() // { // var span = ReadAlignedSpan(sizeof(UInt16)); // var r = BitConverter.ToUInt16(span); // if (Debug) Console.WriteLine("ReadUInt16 " + r); // return r; // } // // public Int32 ReadInt32() // { // var span = ReadAlignedSpan(sizeof(Int32)); // var r = BitConverter.ToInt32(span); // if (Debug) Console.WriteLine("ReadInt32 " + r); // return r; // } // // public UInt32 ReadUInt32() // { // var span = ReadAlignedSpan(sizeof(UInt32)); // var r = BitConverter.ToUInt32(span); // if (Debug) Console.WriteLine("ReadUInt32 " + r); // return r; // } // // public Int64 ReadInt64() // { // var span = ReadAlignedSpan(sizeof(Int64)); // var r = BitConverter.ToInt64(span); // if (Debug) Console.WriteLine("ReadInt64 " + r); // return r; // } // // public UInt64 ReadUInt64() // { // var span = ReadAlignedSpan(sizeof(UInt64)); // var r = BitConverter.ToUInt64(span); // if (Debug) Console.WriteLine("ReadUInt64 " + r); // return r; // } // // public Boolean ReadBoolean() // { // var uInt32 = ReadUInt32(); // // var r = uInt32 switch // { // 0 => false, // 1 => true, // _ => throw new ProtocolException($"Read value {uInt32} at position " + // $"{BytesRead - sizeof(UInt32)} " + // "while expecting boolean (0/1)") // }; // // if (Debug) Console.WriteLine("ReadBoolean " + r); // return r; // } // // public Double ReadDouble() // { // var span = ReadAlignedSpan(sizeof(Double)); // var r = BitConverter.ToDouble(span); // if (Debug) Console.WriteLine("ReadDouble " + r); // return r; // } // // public String ReadString() // { // var strLen = ReadInt32(); // var span = ReadSegment(strLen); // var str = Encoding.UTF8.GetString(span); // if (Debug) Console.WriteLine("ReadString " + str); // SkipNull(); // return str; // } // // public ObjectPath ReadObjectPath() // { // if (Debug) Console.WriteLine("ReadObjectPath:"); // return ReadString(); // } // // public Signature ReadSignature() // { // if (Debug) Console.WriteLine("ReadSignature:"); // var sigLen = ReadByte(); // var span = ReadSegment(sigLen); // var sig = Encoding.ASCII.GetString(span); // only ascii chars allowed in sig // SkipNull(); // return Signature.FromString(sig); // } // // public Variant ReadVariant() // { // if (Debug) Console.WriteLine("ReadVariant:"); // var signature = ReadSignature(); // var value = signature.Read(this); // // return new Variant(value, signature); // } // // public void AlignForComposite() => Align(8); // structs/arrays/dict elements are always 8-aligned // // private ReadOnlySpan ReadAlignedSpan(Int32 size) // { // Align(size); // // var start = BytesRead; // var span = ReadSegment(size); // // if (SwapEndian) // Array.Reverse(span.Array!, span.Offset + start, size); // // return span; // } // // private void SkipNull() // { // if (ReadByte() != 0) // throw new ProtocolException("Read a non-zero byte while expecting a null byte"); // } // // private void Align(Int32 alignment) // { // while (BytesRead % alignment != 0) // SkipNull(); // } // // public override String ToString() => $"@{BytesRead}"; // }