// Spludlow Software // Copyright © Samuel P. Ludlow 2020 All Rights Reserved // Distributed under the terms of the GNU General Public License version 3 // Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE // https://www.spludlow.co.uk/LICENCE.TXT // The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission // v1.14 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using System.Reflection; namespace Spludlow.Io { public class BinaryIO { // "Little Endian" means that the low-order byte of the number is stored in memory at the lowest address, and the high-order byte at the highest address. (The little end comes first.) // 0, 1, 2, 3 // Intel processors (those used in PC's) use "Little Endian" byte order. // "Big Endian" means that the high-order byte of the number is stored in memory at the lowest address, and the low-order byte at the highest address. (The big end comes first.) // 3, 2, 1, 0 // Motorola processors (those used in OLD Mac's) use "Big Endian" byte order. public static string ReadString(byte[] data, int index, int length) { return ReadString(data, index, length, Encoding.Default); } public static string ReadString(byte[] data, int index, int length, Encoding encoding) { return encoding.GetString(data, index, length).Trim(); } public static string ReadString(BinaryReader reader, int length, Encoding encoding) { byte[] data = reader.ReadBytes(length); return encoding.GetString(data, 0, length); } public static long ReadBinary(byte[] data, object instance, bool bigEndian) { return ReadBinary(data, instance, bigEndian, null); } public static long ReadBinary(byte[] data, object instance, bool bigEndian, int[] stringLengths) { using (MemoryStream stream = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(stream)) { return ReadBinary(reader, instance, bigEndian, stringLengths); } } } public static long ReadBinary(BinaryReader reader, object instance, bool bigEndian) { return ReadBinary(reader, instance, bigEndian, null); } public static long ReadBinary(BinaryReader reader, object instance, bool bigEndian, int[] stringLengths) { long start = reader.BaseStream.Position; int stringLengthIndex = 0; foreach (FieldInfo fieldInfo in instance.GetType().GetFields()) { string typeName = fieldInfo.FieldType.Name; object result; if (typeName == "String") { result = (new String(reader.ReadChars(stringLengths[stringLengthIndex]))).Trim(); ++stringLengthIndex; } else { if (typeName == "Byte") result = reader.ReadByte(); else result = Spludlow.Reflections.Invoke("Spludlow", "Spludlow.Io.BinaryIO", "Read" + typeName, new object[] { reader, bigEndian }); } fieldInfo.SetValue(instance, result); } return reader.BaseStream.Position - start; } private const int Size16 = sizeof(Int16); public static Int16 ReadInt16(BinaryReader reader, bool bigEndian) { if (bigEndian == false) return reader.ReadInt16(); byte[] buffer = reader.ReadBytes(Size16); if (buffer.Length != Size16) throw new ApplicationException("Binary Read; Incomplete bytes."); return ReadInt16(buffer, 0, bigEndian); } public static Int16 ReadInt16(byte[] buffer, int offset, bool bigEndian) { if (bigEndian == false) return BitConverter.ToInt16(buffer, offset); byte[] number = new byte[2]; number[0] = buffer[offset + 1]; number[1] = buffer[offset + 0]; return BitConverter.ToInt16(number, 0); } public static UInt16 ReadUInt16(BinaryReader reader, bool bigEndian) { if (bigEndian == false) return reader.ReadUInt16(); byte[] buffer = reader.ReadBytes(Size16); if (buffer.Length != Size16) throw new ApplicationException("Binary Read; Incomplete bytes."); return ReadUInt16(buffer, 0, bigEndian); } public static UInt16 ReadUInt16(byte[] buffer, int offset, bool bigEndian) { if (bigEndian == false) return BitConverter.ToUInt16(buffer, offset); byte[] number = new byte[2]; number[0] = buffer[offset + 1]; number[1] = buffer[offset + 0]; return BitConverter.ToUInt16(number, 0); } private const int Size32 = sizeof(Int32); public static Int32 ReadInt32(BinaryReader reader, bool bigEndian) { if (bigEndian == false) return reader.ReadInt32(); byte[] buffer = reader.ReadBytes(Size32); if (buffer.Length != Size32) throw new ApplicationException("Binary Read; Incomplete bytes."); return ReadInt32(buffer, 0, bigEndian); } public static Int32 ReadInt32(byte[] buffer, int offset, bool bigEndian) { if (bigEndian == false) return BitConverter.ToInt32(buffer, offset); byte[] number = new byte[4]; number[0] = buffer[offset + 3]; number[1] = buffer[offset + 2]; number[2] = buffer[offset + 1]; number[3] = buffer[offset + 0]; return BitConverter.ToInt32(number, 0); } public static UInt32 ReadUInt32(BinaryReader reader, bool bigEndian) { if (bigEndian == false) return reader.ReadUInt32(); byte[] buffer = reader.ReadBytes(Size32); if (buffer.Length != Size32) throw new ApplicationException("Binary Read; Incomplete bytes."); return ReadUInt32(buffer, 0, bigEndian); } public static UInt32 ReadUInt32(byte[] buffer, int offset, bool bigEndian) { if (bigEndian == false) return BitConverter.ToUInt32(buffer, offset); byte[] number = new byte[4]; number[0] = buffer[offset + 3]; number[1] = buffer[offset + 2]; number[2] = buffer[offset + 1]; number[3] = buffer[offset + 0]; return BitConverter.ToUInt32(number, 0); } private const int Size64 = sizeof(Int64); public static Int64 ReadInt64(BinaryReader reader, bool bigEndian) { if (bigEndian == false) return reader.ReadInt64(); byte[] buffer = reader.ReadBytes(Size64); if (buffer.Length != Size64) throw new ApplicationException("Binary Read; Incomplete bytes."); return ReadInt64(buffer, 0, bigEndian); } public static Int64 ReadInt64(byte[] buffer, int offset, bool bigEndian) { if (bigEndian == false) return BitConverter.ToInt64(buffer, offset); byte[] number = new byte[8]; number[0] = buffer[offset + 7]; number[1] = buffer[offset + 6]; number[2] = buffer[offset + 5]; number[3] = buffer[offset + 4]; number[4] = buffer[offset + 3]; number[5] = buffer[offset + 2]; number[6] = buffer[offset + 1]; number[7] = buffer[offset + 0]; return BitConverter.ToInt64(number, 0); } public static UInt64 ReadUInt64(BinaryReader reader, bool bigEndian) { if (bigEndian == false) return reader.ReadUInt64(); byte[] buffer = reader.ReadBytes(Size64); if (buffer.Length != Size64) throw new ApplicationException("Binary Read; Incomplete bytes."); return ReadUInt64(buffer, 0, bigEndian); } public static UInt64 ReadUInt64(byte[] buffer, int offset, bool bigEndian) { if (bigEndian == false) return BitConverter.ToUInt64(buffer, offset); byte[] number = new byte[8]; number[0] = buffer[offset + 7]; number[1] = buffer[offset + 6]; number[2] = buffer[offset + 5]; number[3] = buffer[offset + 4]; number[4] = buffer[offset + 3]; number[5] = buffer[offset + 2]; number[6] = buffer[offset + 1]; number[7] = buffer[offset + 0]; return BitConverter.ToUInt64(number, 0); } public static long FindBinaryPattern(byte[] data, byte[] pattern) { using (MemoryStream stream = new MemoryStream(data)) { return FindBinaryPattern(stream, pattern); } } public static long FindBinaryPattern(string filename, byte[] pattern) { using (FileStream stream = new FileStream(filename, FileMode.Open)) { return FindBinaryPattern(stream, pattern); } } public static long FindBinaryPattern(Stream stream, byte[] pattern) { byte[] buffer = new byte[1024 * 1024]; int patternIndex = 0; int read; while ((read = stream.Read(buffer, 0, buffer.Length)) > 0) { for (int bufferIndex = 0; bufferIndex < read; ++bufferIndex) { if (buffer[bufferIndex] == pattern[patternIndex]) { ++patternIndex; if (patternIndex == pattern.Length) return stream.Position - (read - bufferIndex) - pattern.Length + 1; } else { patternIndex = 0; } } } return -1; } } }