From 3ba34b9bd0057ee67ef89c2fed42920aaa08a958 Mon Sep 17 00:00:00 2001 From: Adrian Date: Mon, 22 Feb 2016 00:31:21 +0100 Subject: [PATCH 1/2] Refactor binary reader/writer --- .../AdrianKousz.Util/ExtendedBinaryReader.cs | 17 +++-- .../AdrianKousz.Util/ExtendedBinaryWriter.cs | 66 ++++++++++--------- .../NonDisposingStreamWrapper.cs | 2 - 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/src/main/AdrianKousz.Util/ExtendedBinaryReader.cs b/src/main/AdrianKousz.Util/ExtendedBinaryReader.cs index 8cc9ff2..c60dcfc 100644 --- a/src/main/AdrianKousz.Util/ExtendedBinaryReader.cs +++ b/src/main/AdrianKousz.Util/ExtendedBinaryReader.cs @@ -30,14 +30,17 @@ namespace AdrianKousz.Util return ReadInt32() != 0; } - public string ReadString(int len) { return ReadString(len, false); } - public string ReadStringInt16() { return ReadString(ReadInt16(), false); } - public string ReadStringInt32() { return ReadString(ReadInt32(), false); } - public string ReadZString(int len) { return ReadString(len, true); } - public string ReadZStringInt16() { return ReadString(ReadInt16(), true); } - public string ReadZStringInt32() { return ReadString(ReadInt32(), true); } + public string ReadStringInternal(int len) { return ReadStringInternal(len, false); } + public string ReadStringByte() { return ReadStringInternal(ReadByte(), false); } + public string ReadStringInt16() { return ReadStringInternal(ReadInt16(), false); } + public string ReadStringInt32() { return ReadStringInternal(ReadInt32(), false); } - private string ReadString(int len, bool expectNull) + public string ReadZString(int len) { return ReadStringInternal(len, true); } + public string ReadZStringByte() { return ReadStringInternal(ReadByte(), true); } + public string ReadZStringInt16() { return ReadStringInternal(ReadInt16(), true); } + public string ReadZStringInt32() { return ReadStringInternal(ReadInt32(), true); } + + private string ReadStringInternal(int len, bool expectNull) { if (len == 0) return ""; var array = ReadBytes(len); diff --git a/src/main/AdrianKousz.Util/ExtendedBinaryWriter.cs b/src/main/AdrianKousz.Util/ExtendedBinaryWriter.cs index 1c194b4..049a98d 100644 --- a/src/main/AdrianKousz.Util/ExtendedBinaryWriter.cs +++ b/src/main/AdrianKousz.Util/ExtendedBinaryWriter.cs @@ -9,6 +9,7 @@ namespace AdrianKousz.Util public Encoding Encoding { get; private set; } private const string ErrorChooseMethod = "Choose string writing method"; + private const string ErrorStringTooLong = "String too long"; public ExtendedBinaryWriter(Stream stream, Encoding enc) : base(stream, enc) @@ -27,38 +28,17 @@ namespace AdrianKousz.Util else Write((Int32)0); } - public void WriteZStringRaw(string value) { WriteStringRaw(value + "\0"); } - public void WriteZStringInt16(string value) { WriteStringInt16(value + "\0"); } - public void WriteZStringInt32(string value) { WriteStringInt32(value + "\0"); } + public void WriteString(string value, int len) { WriteStringInternal(value, len, TypeCode.Empty); } + public void WriteStringByte(string value) { WriteStringInternal(value, 0, TypeCode.Byte); } + public void WriteStringInt16(string value) { WriteStringInternal(value, 0, TypeCode.Int16); } + public void WriteStringInt32(string value) { WriteStringInternal(value, 0, TypeCode.Int32); } + public void WriteStringRaw(string value) { WriteStringInternal(value, 0, TypeCode.Empty); } - public void WriteStringRaw(string value) - { - var array = Encoding.GetBytes(value); - Write(array); - } - - public void WriteStringInt16(string value) - { - var array = Encoding.GetBytes(value); - var len = (Int16)array.Length; - Write(len); - Write(array); - } - - public void WriteStringInt32(string value) - { - var array = Encoding.GetBytes(value); - var len = (Int32)array.Length; - Write(len); - Write(array); - } - - public void WriteStringPadded(string value, int len) - { - var array = new byte[len]; - Encoding.GetBytes(value, 0, value.Length, array, 0); - Write(array); - } + public void WriteZString(string value, int len) { WriteStringInternal(value + "\0", len, TypeCode.Empty); } + public void WriteZStringByte(string value) { WriteStringInternal(value + "\0", 0, TypeCode.Byte); } + public void WriteZStringInt16(string value) { WriteStringInternal(value + "\0", 0, TypeCode.Int16); } + public void WriteZStringInt32(string value) { WriteStringInternal(value + "\0", 0, TypeCode.Int32); } + public void WriteZStringRaw(string value) { WriteStringInternal(value + "\0", 0, TypeCode.Empty); } public int GetByteCount(string value) { @@ -69,5 +49,29 @@ namespace AdrianKousz.Util { return Encoding.GetByteCount(value + "\0"); } + + private void WriteStringInternal(string value, int len, TypeCode typecode) + { + byte[] array; + if (len == 0) { + array = Encoding.GetBytes(value); + len = array.Length; + } else { + if (len < GetByteCount(value)) + throw new ArgumentOutOfRangeException(ErrorStringTooLong); + array = new byte[len]; + Encoding.GetBytes(value, 0, value.Length, array, 0); + } + + switch (typecode) { + case TypeCode.Empty: break; + case TypeCode.Int32: Write(checked((Int32)len)); break; + case TypeCode.Int16: Write(checked((Int16)len)); break; + case TypeCode.Byte: Write(checked((Byte)len)); break; + default: throw new ArgumentException(); + } + + Write(array); + } } } diff --git a/src/main/AdrianKousz.Util/NonDisposingStreamWrapper.cs b/src/main/AdrianKousz.Util/NonDisposingStreamWrapper.cs index d11b2dd..bccc934 100644 --- a/src/main/AdrianKousz.Util/NonDisposingStreamWrapper.cs +++ b/src/main/AdrianKousz.Util/NonDisposingStreamWrapper.cs @@ -11,8 +11,6 @@ namespace AdrianKousz.Util { public sealed class NonDisposingStreamWrapper : Stream { - private bool closed = false; - public Stream BaseStream { get; private set; } public NonDisposingStreamWrapper(Stream stream) From 34b3ff87222a224b8fbb872e9f998b54c1624597 Mon Sep 17 00:00:00 2001 From: Adrian Date: Mon, 22 Feb 2016 16:33:04 +0100 Subject: [PATCH 2/2] Add UnsafeBitmap class for image manipulation --- src/main/AdrianKousz.Util/UnsafeBitmap.cs | 65 +++++++++++++++++++++++ src/main/ExUtil.csproj | 6 +++ 2 files changed, 71 insertions(+) create mode 100644 src/main/AdrianKousz.Util/UnsafeBitmap.cs diff --git a/src/main/AdrianKousz.Util/UnsafeBitmap.cs b/src/main/AdrianKousz.Util/UnsafeBitmap.cs new file mode 100644 index 0000000..b4ff7c8 --- /dev/null +++ b/src/main/AdrianKousz.Util/UnsafeBitmap.cs @@ -0,0 +1,65 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; + +namespace AdrianKousz.Util +{ + public unsafe class UnsafeBitmap : IDisposable + { + private const string ErrorNotLocked = "Bitmap not locked"; + private const string ErrorAlreadyLocked = "Bitmap already locked"; + + private Bitmap bmp; + private BitmapData bmpdat; + + public UnsafeBitmap(Bitmap bmp) + : this(bmp, false, true) { } + + public UnsafeBitmap(Bitmap bmp, bool write) + : this(bmp, write, true) { } + + public UnsafeBitmap(Bitmap bmp, bool write, bool locknow) + { + this.bmp = bmp; + this.bmpdat = null; + if (locknow) + Lock(write ? ImageLockMode.ReadWrite : ImageLockMode.ReadOnly); + } + + public void Dispose() + { + if (bmp == null) return; + Unlock(); + bmp = null; + } + + public void Lock(ImageLockMode mode) + { + if (bmpdat != null) + throw new InvalidOperationException(ErrorAlreadyLocked); + if (bmp == null) + throw new ObjectDisposedException(null); + var rect = new Rectangle(0, 0, bmp.Width, bmp.Height); + bmpdat = bmp.LockBits(rect, mode, bmp.PixelFormat); + } + + public void Unlock() + { + bmp.UnlockBits(bmpdat); + bmpdat = null; + } + + public int Height { get { CheckLocked(); return bmpdat.Height; } } + public PixelFormat PixelFormat { get { CheckLocked(); return bmpdat.PixelFormat; } } + public byte* Scan0 { get { CheckLocked(); return (byte*)bmpdat.Scan0.ToPointer(); } } + public int Stride { get { CheckLocked(); return bmpdat.Stride; } } + public int Width { get { CheckLocked(); return bmpdat.Width; } } + + private void CheckLocked() + { + if (bmpdat == null) + throw new InvalidOperationException(ErrorNotLocked); + } + } +} + diff --git a/src/main/ExUtil.csproj b/src/main/ExUtil.csproj index 59ed74a..e506992 100644 --- a/src/main/ExUtil.csproj +++ b/src/main/ExUtil.csproj @@ -18,6 +18,7 @@ prompt 4 false + true full @@ -26,6 +27,7 @@ prompt 4 false + true @@ -39,5 +41,9 @@ + + + + \ No newline at end of file