using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace FSO.Files.Utils
{
///
/// The order to read bytes in.
///
public enum ByteOrder
{
BIG_ENDIAN,
LITTLE_ENDIAN
}
///
/// IOBuffer is a very basic wrapper over System.BinaryReader that inherits from IDisposable.
///
public class IoBuffer : IDisposable, BCFReadProxy
{
private Stream Stream;
private BinaryReader Reader;
public ByteOrder ByteOrder = ByteOrder.BIG_ENDIAN;
///
/// Creates a new IOBuffer instance from a stream.
///
///
public IoBuffer(Stream stream)
{
this.Stream = stream;
this.Reader = new BinaryReader(stream);
}
///
/// More to read in this stream?
///
public bool HasMore
{
get
{
return Stream.Position < Stream.Length - 1;
}
}
///
/// Skips a number of bytes in the current stream, starting from the current position.
///
/// Number of bytes to skip.
public void Skip(long numBytes)
{
Reader.BaseStream.Seek(numBytes, SeekOrigin.Current);
}
///
/// Seeks in the current stream.
///
/// Where to start from.
/// The offset to seek to.
public void Seek(SeekOrigin origin, long offset)
{
Reader.BaseStream.Seek(offset, origin);
}
public long Position => Stream.Position;
///
/// Reads a variable length unsigned integer from the current stream.
///
/// A uint.
public uint ReadVarLen()
{
uint result = 0;
int shift = 0;
byte read = 0x80;
while ((read&0x80) > 0)
{
read = ReadByte();
result |= (uint)((read & 0x7F) << shift);
shift += 7;
}
return result;
}
///
/// Reads an unsigned 16bit integer from the current stream.
///
/// A ushort.
public ushort ReadUInt16()
{
var value = Reader.ReadUInt16();
if (ByteOrder == ByteOrder.BIG_ENDIAN)
{
value = Endian.SwapUInt16(value);
}
return value;
}
///
/// Reads a 16bit integer from the current stream.
///
/// A short.
public short ReadInt16()
{
var value = Reader.ReadInt16();
if (ByteOrder == ByteOrder.BIG_ENDIAN)
{
value = Endian.SwapInt16(value);
}
return value;
}
///
/// Reads a 32bit integer from the current stream.
///
/// An int.
public int ReadInt32()
{
var value = Reader.ReadInt32();
if (ByteOrder == ByteOrder.BIG_ENDIAN)
{
value = Endian.SwapInt32(value);
}
return value;
}
///
/// Reads a 64bit integer from the current stream.
///
/// An int.
public long ReadInt64()
{
var value = Reader.ReadInt64();
if (ByteOrder == ByteOrder.BIG_ENDIAN)
{
value = Endian.SwapInt64(value);
}
return value;
}
///
/// Reads an unsigned 32bit integer from the current stream.
///
/// A uint.
public uint ReadUInt32()
{
var value = Reader.ReadUInt32();
if (ByteOrder == ByteOrder.BIG_ENDIAN)
{
value = Endian.SwapUInt32(value);
}
return value;
}
///
/// Reads a number of ASCII characters from the current stream.
///
/// The number of characters to read.
/// A string, INCLUDING the trailing 0.
public string ReadCString(int num)
{
return ReadCString(num, false);
}
///
/// Reads a number of ASCII characters from the current stream.
///
/// The number of characters to read.
/// Trim the trailing 0?
/// A string, with or without the trailing 0.
public string ReadCString(int num, bool trimNull)
{
var result = ASCIIEncoding.ASCII.GetString(Reader.ReadBytes(num));
if (trimNull)
{
/** Trim on \0 **/
var io = result.IndexOf('\0');
if (io != -1)
{
result = result.Substring(0, io);
}
}
return result;
}
///
/// Reads a byte from the current stream.
///
/// A byte.
public byte ReadByte()
{
return Reader.ReadByte();
}
///
/// Reads a number of bytes from the current stream.
///
/// Number of bytes to read.
/// An byte array.
public byte[] ReadBytes(uint num)
{
return Reader.ReadBytes((int)num);
}
///
/// Reads a number of bytes from the current stream.
///
/// Number of bytes to read.
/// An byte array.
public byte[] ReadBytes(int num)
{
return Reader.ReadBytes(num);
}
///
/// Reads a pascal string from the current stream, which is prefixed by a 16bit short.
///
/// A string.
public string ReadLongPascalString()
{
var length = ReadInt16();
return Encoding.ASCII.GetString(Reader.ReadBytes(length));
}
///
/// Reads a C string from the current stream.
///
/// A string.
public string ReadNullTerminatedString()
{
var sb = new StringBuilder();
while (true){
char ch = (char)Reader.ReadByte();
if (ch == '\0'){
break;
}
sb.Append(ch);
}
return sb.ToString();
}
public string ReadNullTerminatedUTF8()
{
var sb = new List();
while (true)
{
var b = Reader.ReadByte();
if (b == 0) break;
sb.Add(b);
}
return Encoding.UTF8.GetString(sb.ToArray());
}
///
/// Reads a pascal string from the current stream.
///
/// A string.
public string ReadVariableLengthPascalString()
{
return Reader.ReadString();
}
///
/// Reads a pascal string from the current stream, prefixed by a byte.
///
/// A string.
public string ReadPascalString()
{
var length = ReadByte();
return Encoding.ASCII.GetString(Reader.ReadBytes(length));
}
///
/// Reads a float from the current stream.
///
/// A float.
[System.Security.SecuritySafeCritical] // auto-generated
public virtual unsafe float ReadFloat()
{
return Reader.ReadSingle();
}
///
/// Sets a mark at the current position in the stream.
///
private long _Mark;
public void Mark()
{
_Mark = Reader.BaseStream.Position;
}
///
/// Seeks in the current stream from the current mark plus the number of bytes.
///
/// The number of bytes to add to the offset (mark).
public void SeekFromMark(long numBytes)
{
Reader.BaseStream.Seek(_Mark + numBytes, SeekOrigin.Begin);
}
#region IDisposable Members
public void Dispose()
{
}
#endregion
///
/// Creates a new IOBuffer instance from a stream.
///
/// A stream.
/// A new IOBuffer instance.
public static IoBuffer FromStream(Stream stream)
{
return new IoBuffer(stream);
}
///
/// Creates a new IOBuffer instance from a stream, using a specified byte order.
///
/// A stream.
/// Byte order to use.
/// A new IOBuffer instance.
public static IoBuffer FromStream(Stream stream, ByteOrder order)
{
var item = FromStream(stream);
item.ByteOrder = order;
return item;
}
///
/// Creates a new IOBuffer instance from a byte array.
///
/// The byte array to use.
/// A new IOBuffer instance.
public static IoBuffer FromBytes(byte[] bytes)
{
return FromStream(new MemoryStream(bytes));
}
///
/// Creates a new IOBuffer instance from a byte array, using a specified byte order.
///
/// The byte array to use.
/// Byte order to use.
/// A new IOBuffer instance.
public static IoBuffer FromBytes(byte[] bytes, ByteOrder order)
{
return FromStream(new MemoryStream(bytes), order);
}
}
}