1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.IO; 9 using System.Linq; 10 11 namespace Antmicro.Renode.Utilities 12 { 13 public static class BinaryReaderExtensions 14 { ReadCString(this BinaryReader @this)15 public static string ReadCString(this BinaryReader @this) 16 { 17 var bytes = Misc.Iterate(@this.ReadByte).TakeWhile(b => b != 0x00).ToArray(); 18 return System.Text.Encoding.Default.GetString(bytes); 19 } 20 } 21 22 public class SafeBinaryReader : BinaryReader 23 { SafeBinaryReader(Stream stream)24 public SafeBinaryReader(Stream stream) : base(stream) 25 { 26 Length = this.BaseStream.Length; 27 } 28 WithLength(long newLength)29 public SafeBinaryReader WithLength(long newLength) 30 { 31 var newReader = new SafeBinaryReader(this.BaseStream, newLength); 32 return newReader; 33 } 34 ReadBoolean()35 public override bool ReadBoolean() 36 { 37 return ExecuteAndHandleError(base.ReadBoolean); 38 } 39 ReadByte()40 public override byte ReadByte() 41 { 42 return ExecuteAndHandleError(base.ReadByte); 43 } 44 ReadBytes(int count)45 public override byte[] ReadBytes(int count) 46 { 47 return ExecuteAndHandleError(delegate { return base.ReadBytes(count); }); 48 } 49 ReadChar()50 public override char ReadChar() 51 { 52 return ExecuteAndHandleError(base.ReadChar); 53 } 54 ReadChars(int count)55 public override char[] ReadChars(int count) 56 { 57 return ExecuteAndHandleError(delegate { return base.ReadChars(count); }); 58 } 59 ReadDecimal()60 public override decimal ReadDecimal() 61 { 62 return ExecuteAndHandleError(base.ReadDecimal); 63 } 64 ReadDouble()65 public override double ReadDouble() 66 { 67 return ExecuteAndHandleError(base.ReadDouble); 68 } 69 ReadInt16()70 public override short ReadInt16() 71 { 72 return ExecuteAndHandleError(base.ReadInt16); 73 } 74 ReadInt32()75 public override int ReadInt32() 76 { 77 return ExecuteAndHandleError(base.ReadInt32); 78 } 79 ReadInt64()80 public override long ReadInt64() 81 { 82 return ExecuteAndHandleError(base.ReadInt64); 83 } 84 ReadSByte()85 public override sbyte ReadSByte() 86 { 87 return ExecuteAndHandleError(base.ReadSByte); 88 } 89 ReadSingle()90 public override float ReadSingle() 91 { 92 return ExecuteAndHandleError(base.ReadSingle); 93 } 94 ReadString()95 public override string ReadString() 96 { 97 return ExecuteAndHandleError(base.ReadString); 98 } 99 ReadUInt16()100 public override ushort ReadUInt16() 101 { 102 return ExecuteAndHandleError(base.ReadUInt16); 103 } 104 ReadUInt32()105 public override uint ReadUInt32() 106 { 107 return ExecuteAndHandleError(base.ReadUInt32); 108 } 109 ReadUInt64()110 public override ulong ReadUInt64() 111 { 112 return ExecuteAndHandleError(base.ReadUInt64); 113 } 114 ReadCString()115 public string ReadCString() 116 { 117 return ExecuteAndHandleError(() => ((BinaryReader)this).ReadCString()); 118 } 119 SkipBytes(long count)120 public bool SkipBytes(long count) 121 { 122 var previousPosition = this.BaseStream.Position; 123 if(previousPosition + count > Length) 124 { 125 return false; 126 } 127 128 var currentPosition = this.BaseStream.Seek(count, SeekOrigin.Current); 129 if(previousPosition + count > currentPosition) 130 { 131 EndOfStreamEvent?.Invoke("Stream ended when skipping bytes"); 132 } 133 134 return (previousPosition + count) == currentPosition; 135 } 136 SeekToEnd()137 public bool SeekToEnd() 138 { 139 if(this.BaseStream.Position == Length) 140 { 141 return false; 142 } 143 this.BaseStream.Seek(Length, SeekOrigin.Begin); 144 return true; 145 } 146 147 public long Length { get; } 148 public bool EOF => BaseStream.Position >= Length; 149 public IDisposable Checkpoint 150 { 151 get 152 { 153 var currentPosition = this.BaseStream.Position; 154 return DisposableWrapper.New(() => this.BaseStream.Seek(currentPosition, SeekOrigin.Begin)); 155 } 156 } 157 158 public Action<string> EndOfStreamEvent; 159 SafeBinaryReader(Stream stream, long length)160 private SafeBinaryReader(Stream stream, long length) : this(stream) 161 { 162 Length = length; 163 } 164 ExecuteAndHandleError(Func<T> func)165 private T ExecuteAndHandleError<T>(Func<T> func) 166 { 167 try 168 { 169 return func(); 170 } 171 catch(EndOfStreamException e) 172 { 173 EndOfStreamEvent?.Invoke(e.Message); 174 return default(T); 175 } 176 } 177 } 178 } 179