/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Collections.ObjectModel; using System.Text; namespace dnSpy.Contracts.Hex.Files { /// /// A /// public class BooleanData : SimpleData { /// /// Constructor /// /// Data span public BooleanData(HexBufferSpan span) : base(span) { if (span.Length != 1) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position public BooleanData(HexBuffer buffer, HexPosition position) : this(new HexBufferSpan(buffer, new HexSpan(position, 1))) { } /// /// Reads the value /// /// public bool ReadValue() => Span.Buffer.ReadByte(Span.Start) != 0; /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteBoolean(ReadValue()); } /// /// A /// public class CharData : SimpleData { /// /// Constructor /// /// Data span public CharData(HexBufferSpan span) : base(span) { if (span.Length != 2) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position public CharData(HexBuffer buffer, HexPosition position) : this(new HexBufferSpan(buffer, new HexSpan(position, 2))) { } /// /// Reads the value /// /// public char ReadValue() => Span.Buffer.ReadChar(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteChar(ReadValue()); } /// /// A /// public class ByteData : SimpleData { /// /// Constructor /// /// Data span public ByteData(HexBufferSpan span) : base(span) { if (span.Length != 1) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position public ByteData(HexBuffer buffer, HexPosition position) : this(new HexBufferSpan(buffer, new HexSpan(position, 1))) { } /// /// Reads the value /// /// public byte ReadValue() => Span.Buffer.ReadByte(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteByte(ReadValue()); } /// /// A /// public class UInt16Data : SimpleData { /// /// Constructor /// /// Data span public UInt16Data(HexBufferSpan span) : base(span) { if (span.Length != 2) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position public UInt16Data(HexBuffer buffer, HexPosition position) : this(new HexBufferSpan(buffer, new HexSpan(position, 2))) { } /// /// Reads the value /// /// public ushort ReadValue() => Span.Buffer.ReadUInt16(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteUInt16(ReadValue()); } /// /// A 24-bit /// public class UInt24Data : SimpleData { /// /// Constructor /// /// Data span public UInt24Data(HexBufferSpan span) : base(span) { if (span.Length != 3) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position public UInt24Data(HexBuffer buffer, HexPosition position) : this(new HexBufferSpan(buffer, new HexSpan(position, 3))) { } /// /// Reads the value /// /// public uint ReadValue() => Span.Buffer.ReadUInt16(Span.Start) | ((uint)Span.Buffer.ReadByte(Span.Start + 2) << 16); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteUInt24(ReadValue()); } /// /// A /// public class UInt32Data : SimpleData { /// /// Constructor /// /// Data span public UInt32Data(HexBufferSpan span) : base(span) { if (span.Length != 4) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position public UInt32Data(HexBuffer buffer, HexPosition position) : this(new HexBufferSpan(buffer, new HexSpan(position, 4))) { } /// /// Reads the value /// /// public uint ReadValue() => Span.Buffer.ReadUInt32(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteUInt32(ReadValue()); } /// /// A /// public class UInt64Data : SimpleData { /// /// Constructor /// /// Data span public UInt64Data(HexBufferSpan span) : base(span) { if (span.Length != 8) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position public UInt64Data(HexBuffer buffer, HexPosition position) : this(new HexBufferSpan(buffer, new HexSpan(position, 8))) { } /// /// Reads the value /// /// public ulong ReadValue() => Span.Buffer.ReadUInt64(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteUInt64(ReadValue()); } /// /// A /// public class SByteData : SimpleData { /// /// Constructor /// /// Data span public SByteData(HexBufferSpan span) : base(span) { if (span.Length != 1) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position public SByteData(HexBuffer buffer, HexPosition position) : this(new HexBufferSpan(buffer, new HexSpan(position, 1))) { } /// /// Reads the value /// /// public sbyte ReadValue() => Span.Buffer.ReadSByte(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteSByte(ReadValue()); } /// /// A /// public class Int16Data : SimpleData { /// /// Constructor /// /// Data span public Int16Data(HexBufferSpan span) : base(span) { if (span.Length != 2) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position public Int16Data(HexBuffer buffer, HexPosition position) : this(new HexBufferSpan(buffer, new HexSpan(position, 2))) { } /// /// Reads the value /// /// public short ReadValue() => Span.Buffer.ReadInt16(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteInt16(ReadValue()); } /// /// A /// public class Int32Data : SimpleData { /// /// Constructor /// /// Data span public Int32Data(HexBufferSpan span) : base(span) { if (span.Length != 4) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position public Int32Data(HexBuffer buffer, HexPosition position) : this(new HexBufferSpan(buffer, new HexSpan(position, 4))) { } /// /// Reads the value /// /// public int ReadValue() => Span.Buffer.ReadInt32(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteInt32(ReadValue()); } /// /// A /// public class Int64Data : SimpleData { /// /// Constructor /// /// Data span public Int64Data(HexBufferSpan span) : base(span) { if (span.Length != 8) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position public Int64Data(HexBuffer buffer, HexPosition position) : this(new HexBufferSpan(buffer, new HexSpan(position, 8))) { } /// /// Reads the value /// /// public long ReadValue() => Span.Buffer.ReadInt64(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteInt64(ReadValue()); } /// /// A /// public class SingleData : SimpleData { /// /// Constructor /// /// Data span public SingleData(HexBufferSpan span) : base(span) { if (span.Length != 4) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position public SingleData(HexBuffer buffer, HexPosition position) : this(new HexBufferSpan(buffer, new HexSpan(position, 4))) { } /// /// Reads the value /// /// public float ReadValue() => Span.Buffer.ReadSingle(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteSingle(ReadValue()); } /// /// A /// public class DoubleData : SimpleData { /// /// Constructor /// /// Data span public DoubleData(HexBufferSpan span) : base(span) { if (span.Length != 8) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position public DoubleData(HexBuffer buffer, HexPosition position) : this(new HexBufferSpan(buffer, new HexSpan(position, 8))) { } /// /// Reads the value /// /// public double ReadValue() => Span.Buffer.ReadDouble(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteDouble(ReadValue()); } /// /// A /// public class DecimalData : SimpleData { /// /// Constructor /// /// Data span public DecimalData(HexBufferSpan span) : base(span) { if (span.Length != 16) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position public DecimalData(HexBuffer buffer, HexPosition position) : this(new HexBufferSpan(buffer, new HexSpan(position, 16))) { } static decimal ReadDecimal(HexBuffer buffer, HexPosition position) { var bits = new int[4] { buffer.ReadInt32(position), // lo buffer.ReadInt32(position + 4), // mid buffer.ReadInt32(position + 8), // hi buffer.ReadInt32(position + 0x0C), // flags }; try { return new decimal(bits); } catch (ArgumentException) { } return decimal.Zero; } /// /// Reads the value /// /// public decimal ReadValue() => ReadDecimal(Span.Buffer, Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteDecimal(ReadValue()); } /// /// Flags data /// public abstract class FlagsData : SimpleData { /// /// Gets all flag infos /// public ReadOnlyCollection FlagInfos { get; } /// /// Constructor /// /// Data span /// Flag infos protected FlagsData(HexBufferSpan span, ReadOnlyCollection flagInfos) : base(span) => FlagInfos = flagInfos ?? throw new ArgumentNullException(nameof(flagInfos)); } /// /// A flags field /// public class ByteFlagsData : FlagsData { /// /// Constructor /// /// Data span /// Flag infos public ByteFlagsData(HexBufferSpan span, ReadOnlyCollection flagInfos) : base(span, flagInfos) { if (span.Length != 1) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position /// Flag infos public ByteFlagsData(HexBuffer buffer, HexPosition position, ReadOnlyCollection flagInfos) : this(new HexBufferSpan(buffer, new HexSpan(position, 1)), flagInfos) { } /// /// Reads the value /// /// public byte ReadValue() => Span.Buffer.ReadByte(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteFlags(ReadValue(), FlagInfos); } /// /// A flags field /// public class UInt16FlagsData : FlagsData { /// /// Constructor /// /// Data span /// Flag infos public UInt16FlagsData(HexBufferSpan span, ReadOnlyCollection flagInfos) : base(span, flagInfos) { if (span.Length != 2) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position /// Flag infos public UInt16FlagsData(HexBuffer buffer, HexPosition position, ReadOnlyCollection flagInfos) : this(new HexBufferSpan(buffer, new HexSpan(position, 2)), flagInfos) { } /// /// Reads the value /// /// public ushort ReadValue() => Span.Buffer.ReadUInt16(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteFlags(ReadValue(), FlagInfos); } /// /// A flags field /// public class UInt32FlagsData : FlagsData { /// /// Constructor /// /// Data span /// Flag infos public UInt32FlagsData(HexBufferSpan span, ReadOnlyCollection flagInfos) : base(span, flagInfos) { if (span.Length != 4) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position /// Flag infos public UInt32FlagsData(HexBuffer buffer, HexPosition position, ReadOnlyCollection flagInfos) : this(new HexBufferSpan(buffer, new HexSpan(position, 4)), flagInfos) { } /// /// Reads the value /// /// public uint ReadValue() => Span.Buffer.ReadUInt32(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteFlags(ReadValue(), FlagInfos); } /// /// A flags field /// public class UInt64FlagsData : FlagsData { /// /// Constructor /// /// Data span /// Flag infos public UInt64FlagsData(HexBufferSpan span, ReadOnlyCollection flagInfos) : base(span, flagInfos) { if (span.Length != 8) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position /// Flag infos public UInt64FlagsData(HexBuffer buffer, HexPosition position, ReadOnlyCollection flagInfos) : this(new HexBufferSpan(buffer, new HexSpan(position, 8)), flagInfos) { } /// /// Reads the value /// /// public ulong ReadValue() => Span.Buffer.ReadUInt64(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteFlags(ReadValue(), FlagInfos); } /// /// Enum data /// public abstract class EnumData : SimpleData { /// /// Gets all enum field infos /// public ReadOnlyCollection EnumFieldInfos { get; } /// /// Constructor /// /// Data span /// Enum field infos protected EnumData(HexBufferSpan span, ReadOnlyCollection enumFieldInfos) : base(span) => EnumFieldInfos = enumFieldInfos ?? throw new ArgumentNullException(nameof(enumFieldInfos)); } /// /// A enum field /// public class ByteEnumData : EnumData { /// /// Constructor /// /// Data span /// Enum field infos public ByteEnumData(HexBufferSpan span, ReadOnlyCollection enumFieldInfos) : base(span, enumFieldInfos) { if (span.Length != 1) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position /// Enum field infos public ByteEnumData(HexBuffer buffer, HexPosition position, ReadOnlyCollection enumFieldInfos) : this(new HexBufferSpan(buffer, new HexSpan(position, 1)), enumFieldInfos) { } /// /// Reads the value /// /// public byte ReadValue() => Span.Buffer.ReadByte(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteEnum(ReadValue(), EnumFieldInfos); } /// /// A enum field /// public class UInt16EnumData : EnumData { /// /// Constructor /// /// Data span /// Enum field infos public UInt16EnumData(HexBufferSpan span, ReadOnlyCollection enumFieldInfos) : base(span, enumFieldInfos) { if (span.Length != 2) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position /// Enum field infos public UInt16EnumData(HexBuffer buffer, HexPosition position, ReadOnlyCollection enumFieldInfos) : this(new HexBufferSpan(buffer, new HexSpan(position, 2)), enumFieldInfos) { } /// /// Reads the value /// /// public ushort ReadValue() => Span.Buffer.ReadUInt16(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteEnum(ReadValue(), EnumFieldInfos); } /// /// A enum field /// public class UInt32EnumData : EnumData { /// /// Constructor /// /// Data span /// Enum field infos public UInt32EnumData(HexBufferSpan span, ReadOnlyCollection enumFieldInfos) : base(span, enumFieldInfos) { if (span.Length != 4) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position /// Enum field infos public UInt32EnumData(HexBuffer buffer, HexPosition position, ReadOnlyCollection enumFieldInfos) : this(new HexBufferSpan(buffer, new HexSpan(position, 4)), enumFieldInfos) { } /// /// Reads the value /// /// public uint ReadValue() => Span.Buffer.ReadUInt32(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteEnum(ReadValue(), EnumFieldInfos); } /// /// A enum field /// public class UInt64EnumData : EnumData { /// /// Constructor /// /// Data span /// Enum field infos public UInt64EnumData(HexBufferSpan span, ReadOnlyCollection enumFieldInfos) : base(span, enumFieldInfos) { if (span.Length != 8) throw new ArgumentOutOfRangeException(nameof(span)); } /// /// Constructor /// /// Buffer /// Position /// Enum field infos public UInt64EnumData(HexBuffer buffer, HexPosition position, ReadOnlyCollection enumFieldInfos) : this(new HexBufferSpan(buffer, new HexSpan(position, 8)), enumFieldInfos) { } /// /// Reads the value /// /// public ulong ReadValue() => Span.Buffer.ReadUInt64(Span.Start); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteEnum(ReadValue(), EnumFieldInfos); } /// /// A /// public class StringData : SimpleData { /// /// Gets the encoding /// public Encoding Encoding { get; } /// /// Constructor /// /// Data span /// Encoding public StringData(HexBufferSpan span, Encoding encoding) : base(span) => Encoding = encoding ?? throw new ArgumentNullException(nameof(encoding)); /// /// Constructor /// /// Buffer /// Position /// String length in bytes /// Encoding public StringData(HexBuffer buffer, HexPosition position, int byteLength, Encoding encoding) : this(new HexBufferSpan(buffer, new HexSpan(position, (uint)byteLength)), encoding) { } /// /// Reads the value /// /// public string ReadValue() => Encoding.GetString(Span.GetData()); /// /// Writes the value /// /// Formatter public override void WriteValue(HexFieldFormatter formatter) => formatter.WriteString(ReadValue()); } }