<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
</Choose>
<ItemGroup>
<Compile Include="BroadcastTests.cs" />
+ <Compile Include="MessageReaderTests.cs" />
<Compile Include="StatisticsTests.cs" />
<Compile Include="TestHelper.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
--- /dev/null
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Hazel.UnitTests
+{
+ [TestClass]
+ public class MessageReaderTests
+ {
+ [TestMethod]
+ public void ReadProperInt()
+ {
+ const int Test1 = int.MaxValue;
+ const int Test2 = int.MinValue;
+
+ var msg = new MessageWriter(128);
+ msg.StartMessage(1);
+ msg.Write(Test1);
+ msg.Write(Test2);
+ msg.EndMessage();
+
+ Assert.AreEqual(11, msg.Length);
+ Assert.AreEqual(msg.Length, msg.Position);
+
+ MessageReader reader = MessageReader.Get(msg.Buffer, 0);
+ Assert.AreEqual(Test1, reader.ReadInt32());
+ Assert.AreEqual(Test2, reader.ReadInt32());
+ }
+
+ [TestMethod]
+ public void ReadProperBool()
+ {
+ const bool Test1 = true;
+ const bool Test2 = false;
+
+ var msg = new MessageWriter(128);
+ msg.StartMessage(1);
+ msg.Write(Test1);
+ msg.Write(Test2);
+ msg.EndMessage();
+
+ Assert.AreEqual(5, msg.Length);
+ Assert.AreEqual(msg.Length, msg.Position);
+
+ MessageReader reader = MessageReader.Get(msg.Buffer, 0);
+
+ Assert.AreEqual(Test1, reader.ReadBoolean());
+ Assert.AreEqual(Test2, reader.ReadBoolean());
+
+ }
+
+ [TestMethod]
+ public void ReadProperString()
+ {
+ const string Test1 = "Hello";
+ string Test2 = new string(' ', 1024);
+ var msg = new MessageWriter(2048);
+ msg.StartMessage(1);
+ msg.Write(Test1);
+ msg.Write(Test2);
+ msg.EndMessage();
+
+ Assert.AreEqual(msg.Length, msg.Position);
+
+ MessageReader reader = MessageReader.Get(msg.Buffer, 0);
+
+ Assert.AreEqual(Test1, reader.ReadString());
+ Assert.AreEqual(Test2, reader.ReadString());
+
+ }
+
+ [TestMethod]
+ public void ReadProperFloat()
+ {
+ const float Test1 = 12.34f;
+
+ var msg = new MessageWriter(2048);
+ msg.StartMessage(1);
+ msg.Write(Test1);
+ msg.EndMessage();
+
+ Assert.AreEqual(7, msg.Length);
+ Assert.AreEqual(msg.Length, msg.Position);
+
+ MessageReader reader = MessageReader.Get(msg.Buffer, 0);
+
+ Assert.AreEqual(Test1, reader.ReadSingle());
+
+ }
+
+ [TestMethod]
+ public void ReadMessageLength()
+ {
+ var msg = new MessageWriter(2048);
+ msg.StartMessage(1);
+ msg.Write(65534);
+ msg.StartMessage(2);
+ msg.Write("HO");
+ msg.EndMessage();
+ msg.EndMessage();
+
+ Assert.AreEqual(msg.Length, msg.Position);
+
+ MessageReader reader = MessageReader.Get(msg.Buffer, 0);
+ Assert.AreEqual(1, reader.Tag);
+ Assert.AreEqual(65534, reader.ReadInt32()); // Content
+ var sub = reader.ReadMessage();
+ Assert.AreEqual(2, sub.Tag);
+ Assert.AreEqual("HO", sub.ReadString());
+
+ }
+
+ [TestMethod]
+ public void GetLittleEndian()
+ {
+ Assert.IsTrue(MessageWriter.IsLittleEndian());
+ }
+ }
+}
\ No newline at end of file
+++ /dev/null
-using System.IO;
-
-namespace Hazel
-{
- ///
- public static class BinaryReaderExtensions
- {
- ///
- public static uint ReadPackedUInt32(this BinaryReader reader)
- {
- bool readMore = true;
- int shift = 0;
- uint output = 0;
-
- while (readMore)
- {
- byte b = reader.ReadByte();
- if (b >= 0x80)
- {
- readMore = true;
- b ^= 0x80;
- }
- else
- {
- readMore = false;
- }
-
- output |= (uint)(b << shift);
- shift += 7;
- }
-
- return output;
- }
-
- ///
- public static int ReadPackedInt32(this BinaryReader reader)
- {
- return (int)reader.ReadPackedUInt32();
- }
-
- ///
- public static byte[] ReadBytesAndSize(this BinaryReader reader)
- {
- int len = (int)reader.ReadPackedUInt32();
- return reader.ReadBytes(len);
- }
- }
-}
\ No newline at end of file
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <DocumentationFile>bin\Release\Hazel.XML</DocumentationFile>
+ <DocumentationFile>
+ </DocumentationFile>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
- <Compile Include="BinaryReaderExtensions.cs" />
<Compile Include="Connection.cs" />
<Compile Include="ConnectionEndPoint.cs" />
<Compile Include="ConnectionListener.cs" />
<Compile Include="HazelException.cs" />
<Compile Include="IPMode.cs" />
<Compile Include="IRecyclable.cs" />
+ <Compile Include="MessageReader.cs" />
<Compile Include="NetworkConnection.cs" />
<Compile Include="NetworkConnectionListener.cs" />
<Compile Include="NetworkEndPoint.cs" />
--- /dev/null
+using System;
+using System.Text;
+
+namespace Hazel
+{
+ ///
+ public class MessageReader : IRecyclable
+ {
+ private static readonly ObjectPool<MessageReader> objectPool = new ObjectPool<MessageReader>(() => new MessageReader());
+
+ private byte[] Buffer;
+ public byte Tag;
+ public int End;
+
+ public int Position;
+
+ public static MessageReader Get(byte[] buffer, int offset, int length)
+ {
+ var output = objectPool.GetObject();
+ output.Buffer = buffer;
+ output.Position = offset;
+ output.End = length + offset;
+ output.Tag = output.ReadByte();
+
+ return output;
+ }
+
+ public static MessageReader Get(byte[] buffer, int offset)
+ {
+ var output = objectPool.GetObject();
+ output.Buffer = buffer;
+ output.Position = offset;
+ output.End = output.ReadUInt16() + offset;
+ output.Tag = output.ReadByte();
+
+ return output;
+ }
+
+ ///
+ public MessageReader ReadMessage()
+ {
+ var output = MessageReader.Get(this.Buffer, this.Position);
+ this.Position += output.End;
+ return output;
+ }
+
+ ///
+ public void Recycle()
+ {
+ this.Position = this.End = 0;
+ objectPool.PutObject(this);
+ }
+
+ #region Read Methods
+ public bool ReadBoolean()
+ {
+ byte val = this.Buffer[this.Position++];
+ return val != 0;
+ }
+
+ public sbyte ReadSByte()
+ {
+ return (sbyte)this.Buffer[this.Position++];
+ }
+
+ public byte ReadByte()
+ {
+ return this.Buffer[this.Position++];
+ }
+
+ public ushort ReadUInt16()
+ {
+ ushort output =
+ (ushort)(this.Buffer[Position++]
+ | this.Buffer[Position++] << 8);
+ return output;
+ }
+
+ public int ReadInt32()
+ {
+ int output = this.Buffer[Position++]
+ | this.Buffer[Position++] << 8
+ | this.Buffer[Position++] << 16
+ | this.Buffer[Position++] << 24;
+
+ return output;
+ }
+
+ public unsafe float ReadSingle()
+ {
+ float output = 0;
+ fixed (byte* bufPtr = &this.Buffer[this.Position])
+ {
+ byte* outPtr = (byte*)&output;
+
+ *outPtr = *bufPtr;
+ *(outPtr + 1) = *(bufPtr + 1);
+ *(outPtr + 2) = *(bufPtr + 2);
+ *(outPtr + 3) = *(bufPtr + 3);
+ }
+
+ this.Position += 4;
+ return output;
+ }
+
+ public string ReadString()
+ {
+ int len = this.ReadPackedInt32();
+ string output = UTF8Encoding.UTF8.GetString(this.Buffer, this.Position, len);
+
+ this.Position += len;
+ return output;
+ }
+
+ public byte[] ReadBytesAndSize()
+ {
+ int len = this.ReadPackedInt32();
+ return this.ReadBytes(len);
+ }
+
+ public byte[] ReadBytes(int length)
+ {
+ byte[] output = new byte[length];
+ Array.Copy(this.Buffer, this.Position, output, 0, output.Length);
+ this.Position += output.Length;
+ return output;
+ }
+
+ ///
+ public int ReadPackedInt32()
+ {
+ return (int)this.ReadPackedUInt32();
+ }
+
+ ///
+ public uint ReadPackedUInt32()
+ {
+ bool readMore = true;
+ int shift = 0;
+ uint output = 0;
+
+ while (readMore)
+ {
+ byte b = this.ReadByte();
+ if (b >= 0x80)
+ {
+ readMore = true;
+ b ^= 0x80;
+ }
+ else
+ {
+ readMore = false;
+ }
+
+ output |= (uint)(b << shift);
+ shift += 7;
+ }
+
+ return output;
+ }
+ #endregion
+
+ public unsafe static bool IsLittleEndian()
+ {
+ byte b;
+ unsafe
+ {
+ int i = 1;
+ byte* bp = (byte*)&i;
+ b = *bp;
+ }
+
+ return b == 1;
+ }
+ }
+}
if (this.Position > this.Length) this.Length = this.Position;
}
+ public void Write(sbyte value)
+ {
+ this.Buffer[this.Position++] = (byte)value;
+ if (this.Position > this.Length) this.Length = this.Position;
+ }
+
public void Write(byte value)
{
this.Buffer[this.Position++] = value;
if (this.Position > this.Length) this.Length = this.Position;
}
- public void Write(short value)
+ public void Write(ushort value)
{
this.Buffer[this.Position++] = (byte)value;
this.Buffer[this.Position++] = (byte)(value >> 8);