diff --git a/genProto b/genProto
deleted file mode 100644
index 6c13fc7..0000000
Binary files a/genProto and /dev/null differ
diff --git a/genProto.cmd b/genProto.cmd
deleted file mode 100644
index 179789b..0000000
--- a/genProto.cmd
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-escript.exe "%~dpn0" %*
diff --git a/test/cs/BigEndianBitConverter.cs b/test/cs/BigEndianBitConverter.cs
new file mode 100644
index 0000000..c4cb660
--- /dev/null
+++ b/test/cs/BigEndianBitConverter.cs
@@ -0,0 +1,67 @@
+
+namespace MiscUtil.Conversion
+{
+ ///
+ /// Implementation of EndianBitConverter which converts to/from big-endian
+ /// byte arrays.
+ ///
+ public sealed class BigEndianBitConverter : EndianBitConverter
+ {
+ ///
+ /// Indicates the byte order ("endianess") in which data is converted using this class.
+ ///
+ ///
+ /// Different computer architectures store data using different byte orders. "Big-endian"
+ /// means the most significant byte is on the left end of a word. "Little-endian" means the
+ /// most significant byte is on the right end of a word.
+ ///
+ /// true if this converter is little-endian, false otherwise.
+ public sealed override bool IsLittleEndian()
+ {
+ return false;
+ }
+
+ ///
+ /// Indicates the byte order ("endianess") in which data is converted using this class.
+ ///
+ public sealed override Endianness Endianness
+ {
+ get { return Endianness.BigEndian; }
+ }
+
+ ///
+ /// Copies the specified number of bytes from value to buffer, starting at index.
+ ///
+ /// The value to copy
+ /// The number of bytes to copy
+ /// The buffer to copy the bytes into
+ /// The index to start at
+ protected override void CopyBytesImpl(long value, int bytes, byte[] buffer, int index)
+ {
+ int endOffset = index+bytes-1;
+ for (int i=0; i < bytes; i++)
+ {
+ buffer[endOffset-i] = unchecked((byte)(value&0xff));
+ value = value >> 8;
+ }
+ }
+
+ ///
+ /// Returns a value built from the specified number of bytes from the given buffer,
+ /// starting at index.
+ ///
+ /// The data in byte array format
+ /// The first index to use
+ /// The number of bytes to use
+ /// The value built from the given bytes
+ protected override long FromBytes(byte[] buffer, int startIndex, int bytesToConvert)
+ {
+ long ret = 0;
+ for (int i=0; i < bytesToConvert; i++)
+ {
+ ret = unchecked((ret << 8) | buffer[startIndex+i]);
+ }
+ return ret;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/cs/ConsoleApp2.csproj b/test/cs/ConsoleApp2.csproj
new file mode 100644
index 0000000..003f8fe
--- /dev/null
+++ b/test/cs/ConsoleApp2.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
+
+
diff --git a/test/cs/EndianBinaryReader.cs b/test/cs/EndianBinaryReader.cs
new file mode 100644
index 0000000..c3e1cb0
--- /dev/null
+++ b/test/cs/EndianBinaryReader.cs
@@ -0,0 +1,599 @@
+using System;
+using System.IO;
+using System.Text;
+using MiscUtil.Conversion;
+
+namespace MiscUtil.IO
+{
+ ///
+ /// Equivalent of System.IO.BinaryReader, but with either endianness, depending on
+ /// the EndianBitConverter it is constructed with. No data is buffered in the
+ /// reader; the client may seek within the stream at will.
+ ///
+ public class EndianBinaryReader : IDisposable
+ {
+ #region Fields not directly related to properties
+ ///
+ /// Whether or not this reader has been disposed yet.
+ ///
+ bool disposed=false;
+ ///
+ /// Decoder to use for string conversions.
+ ///
+ Decoder decoder;
+ ///
+ /// Buffer used for temporary storage before conversion into primitives
+ ///
+ byte[] buffer = new byte[16];
+ ///
+ /// Buffer used for temporary storage when reading a single character
+ ///
+ char[] charBuffer = new char[1];
+ ///
+ /// Minimum number of bytes used to encode a character
+ ///
+ int minBytesPerChar;
+ #endregion
+
+ #region Constructors
+ ///
+ /// Equivalent of System.IO.BinaryWriter, but with either endianness, depending on
+ /// the EndianBitConverter it is constructed with.
+ ///
+ /// Converter to use when reading data
+ /// Stream to read data from
+ public EndianBinaryReader (EndianBitConverter bitConverter,
+ Stream stream) : this (bitConverter, stream, Encoding.UTF8)
+ {
+ }
+
+ ///
+ /// Constructs a new binary reader with the given bit converter, reading
+ /// to the given stream, using the given encoding.
+ ///
+ /// Converter to use when reading data
+ /// Stream to read data from
+ /// Encoding to use when reading character data
+ public EndianBinaryReader (EndianBitConverter bitConverter, Stream stream, Encoding encoding)
+ {
+ if (bitConverter==null)
+ {
+ throw new ArgumentNullException("bitConverter");
+ }
+ if (stream==null)
+ {
+ throw new ArgumentNullException("stream");
+ }
+ if (encoding==null)
+ {
+ throw new ArgumentNullException("encoding");
+ }
+ if (!stream.CanRead)
+ {
+ throw new ArgumentException("Stream isn't writable", "stream");
+ }
+ this.stream = stream;
+ this.bitConverter = bitConverter;
+ this.encoding = encoding;
+ this.decoder = encoding.GetDecoder();
+ this.minBytesPerChar = 1;
+
+ if (encoding is UnicodeEncoding)
+ {
+ minBytesPerChar = 2;
+ }
+ }
+ #endregion
+
+ #region Properties
+ EndianBitConverter bitConverter;
+ ///
+ /// The bit converter used to read values from the stream
+ ///
+ public EndianBitConverter BitConverter
+ {
+ get { return bitConverter; }
+ }
+
+ Encoding encoding;
+ ///
+ /// The encoding used to read strings
+ ///
+ public Encoding Encoding
+ {
+ get { return encoding; }
+ }
+
+ Stream stream;
+ ///
+ /// Gets the underlying stream of the EndianBinaryReader.
+ ///
+ public Stream BaseStream
+ {
+ get { return stream; }
+ }
+ #endregion
+
+ #region Public methods
+ ///
+ /// Closes the reader, including the underlying stream..
+ ///
+ public void Close()
+ {
+ Dispose();
+ }
+
+ ///
+ /// Seeks within the stream.
+ ///
+ /// Offset to seek to.
+ /// Origin of seek operation.
+ public void Seek (int offset, SeekOrigin origin)
+ {
+ CheckDisposed();
+ stream.Seek (offset, origin);
+ }
+
+ ///
+ /// Reads a single byte from the stream.
+ ///
+ /// The byte read
+ public byte ReadByte()
+ {
+ ReadInternal(buffer, 1);
+ return buffer[0];
+ }
+
+ ///
+ /// Reads a single signed byte from the stream.
+ ///
+ /// The byte read
+ public sbyte ReadSByte()
+ {
+ ReadInternal(buffer, 1);
+ return unchecked((sbyte)buffer[0]);
+ }
+
+ ///
+ /// Reads a boolean from the stream. 1 byte is read.
+ ///
+ /// The boolean read
+ public bool ReadBoolean()
+ {
+ ReadInternal(buffer, 1);
+ return bitConverter.ToBoolean(buffer, 0);
+ }
+
+ ///
+ /// Reads a 16-bit signed integer from the stream, using the bit converter
+ /// for this reader. 2 bytes are read.
+ ///
+ /// The 16-bit integer read
+ public short ReadInt16()
+ {
+ ReadInternal(buffer, 2);
+ return bitConverter.ToInt16(buffer, 0);
+ }
+
+ ///
+ /// Reads a 32-bit signed integer from the stream, using the bit converter
+ /// for this reader. 4 bytes are read.
+ ///
+ /// The 32-bit integer read
+ public int ReadInt32()
+ {
+ ReadInternal(buffer, 4);
+ return bitConverter.ToInt32(buffer, 0);
+ }
+
+ ///
+ /// Reads a 64-bit signed integer from the stream, using the bit converter
+ /// for this reader. 8 bytes are read.
+ ///
+ /// The 64-bit integer read
+ public long ReadInt64()
+ {
+ ReadInternal(buffer, 8);
+ return bitConverter.ToInt64(buffer, 0);
+ }
+
+ ///
+ /// Reads a 16-bit unsigned integer from the stream, using the bit converter
+ /// for this reader. 2 bytes are read.
+ ///
+ /// The 16-bit unsigned integer read
+ public ushort ReadUInt16()
+ {
+ ReadInternal(buffer, 2);
+ return bitConverter.ToUInt16(buffer, 0);
+ }
+
+ ///
+ /// Reads a 32-bit unsigned integer from the stream, using the bit converter
+ /// for this reader. 4 bytes are read.
+ ///
+ /// The 32-bit unsigned integer read
+ public uint ReadUInt32()
+ {
+ ReadInternal(buffer, 4);
+ return bitConverter.ToUInt32(buffer, 0);
+ }
+
+ ///
+ /// Reads a 64-bit unsigned integer from the stream, using the bit converter
+ /// for this reader. 8 bytes are read.
+ ///
+ /// The 64-bit unsigned integer read
+ public ulong ReadUInt64()
+ {
+ ReadInternal(buffer, 8);
+ return bitConverter.ToUInt64(buffer, 0);
+ }
+
+ ///
+ /// Reads a single-precision floating-point value from the stream, using the bit converter
+ /// for this reader. 4 bytes are read.
+ ///
+ /// The floating point value read
+ public float ReadSingle()
+ {
+ ReadInternal(buffer, 4);
+ return bitConverter.ToSingle(buffer, 0);
+ }
+
+ ///
+ /// Reads a double-precision floating-point value from the stream, using the bit converter
+ /// for this reader. 8 bytes are read.
+ ///
+ /// The floating point value read
+ public double ReadDouble()
+ {
+ ReadInternal(buffer, 8);
+ return bitConverter.ToDouble(buffer, 0);
+ }
+
+ ///
+ /// Reads a decimal value from the stream, using the bit converter
+ /// for this reader. 16 bytes are read.
+ ///
+ /// The decimal value read
+ public decimal ReadDecimal()
+ {
+ ReadInternal(buffer, 16);
+ return bitConverter.ToDecimal(buffer, 0);
+ }
+
+ ///
+ /// Reads a single character from the stream, using the character encoding for
+ /// this reader. If no characters have been fully read by the time the stream ends,
+ /// -1 is returned.
+ ///
+ /// The character read, or -1 for end of stream.
+ public int Read()
+ {
+ int charsRead = Read(charBuffer, 0, 1);
+ if (charsRead==0)
+ {
+ return -1;
+ }
+ else
+ {
+ return charBuffer[0];
+ }
+ }
+
+ ///
+ /// Reads the specified number of characters into the given buffer, starting at
+ /// the given index.
+ ///
+ /// The buffer to copy data into
+ /// The first index to copy data into
+ /// The number of characters to read
+ /// The number of characters actually read. This will only be less than
+ /// the requested number of characters if the end of the stream is reached.
+ ///
+ public int Read(char[] data, int index, int count)
+ {
+ CheckDisposed();
+ if (buffer==null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+ if (index < 0)
+ {
+ throw new ArgumentOutOfRangeException("index");
+ }
+ if (count < 0)
+ {
+ throw new ArgumentOutOfRangeException("index");
+ }
+ if (count+index > data.Length)
+ {
+ throw new ArgumentException
+ ("Not enough space in buffer for specified number of characters starting at specified index");
+ }
+
+ int read=0;
+ bool firstTime=true;
+
+ // Use the normal buffer if we're only reading a small amount, otherwise
+ // use at most 4K at a time.
+ byte[] byteBuffer = buffer;
+
+ if (byteBuffer.Length < count*minBytesPerChar)
+ {
+ byteBuffer = new byte[4096];
+ }
+
+ while (read < count)
+ {
+ int amountToRead;
+ // First time through we know we haven't previously read any data
+ if (firstTime)
+ {
+ amountToRead = count*minBytesPerChar;
+ firstTime=false;
+ }
+ // After that we can only assume we need to fully read "chars left -1" characters
+ // and a single byte of the character we may be in the middle of
+ else
+ {
+ amountToRead = ((count-read-1)*minBytesPerChar)+1;
+ }
+ if (amountToRead > byteBuffer.Length)
+ {
+ amountToRead = byteBuffer.Length;
+ }
+ int bytesRead = TryReadInternal(byteBuffer, amountToRead);
+ if (bytesRead==0)
+ {
+ return read;
+ }
+ int decoded = decoder.GetChars(byteBuffer, 0, bytesRead, data, index);
+ read += decoded;
+ index += decoded;
+ }
+ return read;
+ }
+
+ ///
+ /// Reads the specified number of bytes into the given buffer, starting at
+ /// the given index.
+ ///
+ /// The buffer to copy data into
+ /// The first index to copy data into
+ /// The number of bytes to read
+ /// The number of bytes actually read. This will only be less than
+ /// the requested number of bytes if the end of the stream is reached.
+ ///
+ public int Read(byte[] buffer, int index, int count)
+ {
+ CheckDisposed();
+ if (buffer==null)
+ {
+ throw new ArgumentNullException("buffer");
+ }
+ if (index < 0)
+ {
+ throw new ArgumentOutOfRangeException("index");
+ }
+ if (count < 0)
+ {
+ throw new ArgumentOutOfRangeException("index");
+ }
+ if (count+index > buffer.Length)
+ {
+ throw new ArgumentException
+ ("Not enough space in buffer for specified number of bytes starting at specified index");
+ }
+ int read=0;
+ while (count > 0)
+ {
+ int block = stream.Read(buffer, index, count);
+ if (block==0)
+ {
+ return read;
+ }
+ index += block;
+ read += block;
+ count -= block;
+ }
+ return read;
+ }
+
+ ///
+ /// Reads the specified number of bytes, returning them in a new byte array.
+ /// If not enough bytes are available before the end of the stream, this
+ /// method will return what is available.
+ ///
+ /// The number of bytes to read
+ /// The bytes read
+ public byte[] ReadBytes(int count)
+ {
+ CheckDisposed();
+ if (count < 0)
+ {
+ throw new ArgumentOutOfRangeException("count");
+ }
+ byte[] ret = new byte[count];
+ int index=0;
+ while (index < count)
+ {
+ int read = stream.Read(ret, index, count-index);
+ // Stream has finished half way through. That's fine, return what we've got.
+ if (read==0)
+ {
+ byte[] copy = new byte[index];
+ Buffer.BlockCopy(ret, 0, copy, 0, index);
+ return copy;
+ }
+ index += read;
+ }
+ return ret;
+ }
+
+ ///
+ /// Reads the specified number of bytes, returning them in a new byte array.
+ /// If not enough bytes are available before the end of the stream, this
+ /// method will throw an IOException.
+ ///
+ /// The number of bytes to read
+ /// The bytes read
+ public byte[] ReadBytesOrThrow(int count)
+ {
+ byte[] ret = new byte[count];
+ ReadInternal(ret, count);
+ return ret;
+ }
+
+ ///
+ /// Reads a 7-bit encoded integer from the stream. This is stored with the least significant
+ /// information first, with 7 bits of information per byte of value, and the top
+ /// bit as a continuation flag. This method is not affected by the endianness
+ /// of the bit converter.
+ ///
+ /// The 7-bit encoded integer read from the stream.
+ public int Read7BitEncodedInt()
+ {
+ CheckDisposed();
+
+ int ret=0;
+ for (int shift = 0; shift < 35; shift+=7)
+ {
+ int b = stream.ReadByte();
+ if (b==-1)
+ {
+ throw new EndOfStreamException();
+ }
+ ret = ret | ((b&0x7f) << shift);
+ if ((b & 0x80) == 0)
+ {
+ return ret;
+ }
+ }
+ // Still haven't seen a byte with the high bit unset? Dodgy data.
+ throw new IOException("Invalid 7-bit encoded integer in stream.");
+ }
+
+ ///
+ /// Reads a 7-bit encoded integer from the stream. This is stored with the most significant
+ /// information first, with 7 bits of information per byte of value, and the top
+ /// bit as a continuation flag. This method is not affected by the endianness
+ /// of the bit converter.
+ ///
+ /// The 7-bit encoded integer read from the stream.
+ public int ReadBigEndian7BitEncodedInt()
+ {
+ CheckDisposed();
+
+ int ret=0;
+ for (int i=0; i < 5; i++)
+ {
+ int b = stream.ReadByte();
+ if (b==-1)
+ {
+ throw new EndOfStreamException();
+ }
+ ret = (ret << 7) | (b&0x7f);
+ if ((b & 0x80) == 0)
+ {
+ return ret;
+ }
+ }
+ // Still haven't seen a byte with the high bit unset? Dodgy data.
+ throw new IOException("Invalid 7-bit encoded integer in stream.");
+ }
+
+ ///
+ /// Reads a length-prefixed string from the stream, using the encoding for this reader.
+ /// A 7-bit encoded integer is first read, which specifies the number of bytes
+ /// to read from the stream. These bytes are then converted into a string with
+ /// the encoding for this reader.
+ ///
+ /// The string read from the stream.
+ public string ReadString()
+ {
+ int bytesToRead = Read7BitEncodedInt();
+
+ byte[] data = new byte[bytesToRead];
+ ReadInternal(data, bytesToRead);
+ return encoding.GetString(data, 0, data.Length);
+ }
+
+ #endregion
+
+ #region Private methods
+ ///
+ /// Checks whether or not the reader has been disposed, throwing an exception if so.
+ ///
+ void CheckDisposed()
+ {
+ if (disposed)
+ {
+ throw new ObjectDisposedException("EndianBinaryReader");
+ }
+ }
+
+ ///
+ /// Reads the given number of bytes from the stream, throwing an exception
+ /// if they can't all be read.
+ ///
+ /// Buffer to read into
+ /// Number of bytes to read
+ void ReadInternal (byte[] data, int size)
+ {
+ CheckDisposed();
+ int index=0;
+ while (index < size)
+ {
+ int read = stream.Read(data, index, size-index);
+ if (read==0)
+ {
+ throw new EndOfStreamException
+ (String.Format("End of stream reached with {0} byte{1} left to read.", size-index,
+ size-index==1 ? "s" : ""));
+ }
+ index += read;
+ }
+ }
+
+ ///
+ /// Reads the given number of bytes from the stream if possible, returning
+ /// the number of bytes actually read, which may be less than requested if
+ /// (and only if) the end of the stream is reached.
+ ///
+ /// Buffer to read into
+ /// Number of bytes to read
+ /// Number of bytes actually read
+ int TryReadInternal (byte[] data, int size)
+ {
+ CheckDisposed();
+ int index=0;
+ while (index < size)
+ {
+ int read = stream.Read(data, index, size-index);
+ if (read==0)
+ {
+ return index;
+ }
+ index += read;
+ }
+ return index;
+ }
+ #endregion
+
+ #region IDisposable Members
+ ///
+ /// Disposes of the underlying stream.
+ ///
+ public void Dispose()
+ {
+ if (!disposed)
+ {
+ disposed = true;
+ ((IDisposable)stream).Dispose();
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/test/cs/EndianBinaryWriter.cs b/test/cs/EndianBinaryWriter.cs
new file mode 100644
index 0000000..5feea62
--- /dev/null
+++ b/test/cs/EndianBinaryWriter.cs
@@ -0,0 +1,392 @@
+using System;
+using System.IO;
+using System.Text;
+using MiscUtil.Conversion;
+
+namespace MiscUtil.IO
+{
+ ///
+ /// Equivalent of System.IO.BinaryWriter, but with either endianness, depending on
+ /// the EndianBitConverter it is constructed with.
+ ///
+ public class EndianBinaryWriter : IDisposable
+ {
+ #region Fields not directly related to properties
+ ///
+ /// Whether or not this writer has been disposed yet.
+ ///
+ bool disposed=false;
+ ///
+ /// Buffer used for temporary storage during conversion from primitives
+ ///
+ byte[] buffer = new byte[16];
+ ///
+ /// Buffer used for Write(char)
+ ///
+ char[] charBuffer = new char[1];
+ #endregion
+
+ #region Constructors
+ ///
+ /// Constructs a new binary writer with the given bit converter, writing
+ /// to the given stream, using UTF-8 encoding.
+ ///
+ /// Converter to use when writing data
+ /// Stream to write data to
+ public EndianBinaryWriter (EndianBitConverter bitConverter,
+ Stream stream) : this (bitConverter, stream, Encoding.UTF8)
+ {
+ }
+
+ ///
+ /// Constructs a new binary writer with the given bit converter, writing
+ /// to the given stream, using the given encoding.
+ ///
+ /// Converter to use when writing data
+ /// Stream to write data to
+ /// Encoding to use when writing character data
+ public EndianBinaryWriter (EndianBitConverter bitConverter, Stream stream, Encoding encoding)
+ {
+ if (bitConverter==null)
+ {
+ throw new ArgumentNullException("bitConverter");
+ }
+ if (stream==null)
+ {
+ throw new ArgumentNullException("stream");
+ }
+ if (encoding==null)
+ {
+ throw new ArgumentNullException("encoding");
+ }
+ if (!stream.CanWrite)
+ {
+ throw new ArgumentException("Stream isn't writable", "stream");
+ }
+ this.stream = stream;
+ this.bitConverter = bitConverter;
+ this.encoding = encoding;
+ }
+ #endregion
+
+ #region Properties
+ EndianBitConverter bitConverter;
+ ///
+ /// The bit converter used to write values to the stream
+ ///
+ public EndianBitConverter BitConverter
+ {
+ get { return bitConverter; }
+ }
+
+ Encoding encoding;
+ ///
+ /// The encoding used to write strings
+ ///
+ public Encoding Encoding
+ {
+ get { return encoding; }
+ }
+
+ Stream stream;
+ ///
+ /// Gets the underlying stream of the EndianBinaryWriter.
+ ///
+ public Stream BaseStream
+ {
+ get { return stream; }
+ }
+ #endregion
+
+ #region Public methods
+ ///
+ /// Closes the writer, including the underlying stream.
+ ///
+ public void Close()
+ {
+ Dispose();
+ }
+
+ ///
+ /// Flushes the underlying stream.
+ ///
+ public void Flush()
+ {
+ CheckDisposed();
+ stream.Flush();
+ }
+
+ ///
+ /// Seeks within the stream.
+ ///
+ /// Offset to seek to.
+ /// Origin of seek operation.
+ public void Seek (int offset, SeekOrigin origin)
+ {
+ CheckDisposed();
+ stream.Seek (offset, origin);
+ }
+
+ ///
+ /// Writes a boolean value to the stream. 1 byte is written.
+ ///
+ /// The value to write
+ public void Write (bool value)
+ {
+ bitConverter.CopyBytes(value, buffer, 0);
+ WriteInternal(buffer, 1);
+ }
+
+ ///
+ /// Writes a 16-bit signed integer to the stream, using the bit converter
+ /// for this writer. 2 bytes are written.
+ ///
+ /// The value to write
+ public void Write (short value)
+ {
+ bitConverter.CopyBytes(value, buffer, 0);
+ WriteInternal(buffer, 2);
+ }
+
+ ///
+ /// Writes a 32-bit signed integer to the stream, using the bit converter
+ /// for this writer. 4 bytes are written.
+ ///
+ /// The value to write
+ public void Write (int value)
+ {
+ bitConverter.CopyBytes(value, buffer, 0);
+ WriteInternal(buffer, 4);
+ }
+
+ ///
+ /// Writes a 64-bit signed integer to the stream, using the bit converter
+ /// for this writer. 8 bytes are written.
+ ///
+ /// The value to write
+ public void Write (long value)
+ {
+ bitConverter.CopyBytes(value, buffer, 0);
+ WriteInternal(buffer, 8);
+ }
+
+ ///
+ /// Writes a 16-bit unsigned integer to the stream, using the bit converter
+ /// for this writer. 2 bytes are written.
+ ///
+ /// The value to write
+ public void Write (ushort value)
+ {
+ bitConverter.CopyBytes(value, buffer, 0);
+ WriteInternal(buffer, 2);
+ }
+
+ ///
+ /// Writes a 32-bit unsigned integer to the stream, using the bit converter
+ /// for this writer. 4 bytes are written.
+ ///
+ /// The value to write
+ public void Write (uint value)
+ {
+ bitConverter.CopyBytes(value, buffer, 0);
+ WriteInternal(buffer, 4);
+ }
+
+ ///
+ /// Writes a 64-bit unsigned integer to the stream, using the bit converter
+ /// for this writer. 8 bytes are written.
+ ///
+ /// The value to write
+ public void Write (ulong value)
+ {
+ bitConverter.CopyBytes(value, buffer, 0);
+ WriteInternal(buffer, 8);
+ }
+
+ ///
+ /// Writes a single-precision floating-point value to the stream, using the bit converter
+ /// for this writer. 4 bytes are written.
+ ///
+ /// The value to write
+ public void Write (float value)
+ {
+ bitConverter.CopyBytes(value, buffer, 0);
+ WriteInternal(buffer, 4);
+ }
+
+ ///
+ /// Writes a double-precision floating-point value to the stream, using the bit converter
+ /// for this writer. 8 bytes are written.
+ ///
+ /// The value to write
+ public void Write (double value)
+ {
+ bitConverter.CopyBytes(value, buffer, 0);
+ WriteInternal(buffer, 8);
+ }
+
+ ///
+ /// Writes a decimal value to the stream, using the bit converter for this writer.
+ /// 16 bytes are written.
+ ///
+ /// The value to write
+ public void Write (decimal value)
+ {
+ bitConverter.CopyBytes(value, buffer, 0);
+ WriteInternal(buffer, 16);
+ }
+
+ ///
+ /// Writes a signed byte to the stream.
+ ///
+ /// The value to write
+ public void Write (byte value)
+ {
+ buffer[0] = value;
+ WriteInternal(buffer, 1);
+ }
+
+ ///
+ /// Writes an unsigned byte to the stream.
+ ///
+ /// The value to write
+ public void Write (sbyte value)
+ {
+ buffer[0] = unchecked((byte)value);
+ WriteInternal(buffer, 1);
+ }
+
+ ///
+ /// Writes an array of bytes to the stream.
+ ///
+ /// The values to write
+ public void Write (byte[] value)
+ {
+ if (value == null)
+ {
+ throw (new System.ArgumentNullException("value"));
+ }
+ WriteInternal(value, value.Length);
+ }
+
+ ///
+ /// Writes a portion of an array of bytes to the stream.
+ ///
+ /// An array containing the bytes to write
+ /// The index of the first byte to write within the array
+ /// The number of bytes to write
+ public void Write (byte[] value, int offset, int count)
+ {
+ CheckDisposed();
+ stream.Write(value, offset, count);
+ }
+
+ ///
+ /// Writes a single character to the stream, using the encoding for this writer.
+ ///
+ /// The value to write
+ public void Write(char value)
+ {
+ charBuffer[0] = value;
+ Write(charBuffer);
+ }
+
+ ///
+ /// Writes an array of characters to the stream, using the encoding for this writer.
+ ///
+ /// An array containing the characters to write
+ public void Write(char[] value)
+ {
+ if (value==null)
+ {
+ throw new ArgumentNullException("value");
+ }
+ CheckDisposed();
+ byte[] data = Encoding.GetBytes(value, 0, value.Length);
+ WriteInternal(data, data.Length);
+ }
+
+ ///
+ /// Writes a string to the stream, using the encoding for this writer.
+ ///
+ /// The value to write. Must not be null.
+ /// value is null
+ public void Write(string value)
+ {
+ if (value==null)
+ {
+ throw new ArgumentNullException("value");
+ }
+ CheckDisposed();
+ byte[] data = Encoding.GetBytes(value);
+ Write7BitEncodedInt(data.Length);
+ WriteInternal(data, data.Length);
+ }
+
+ ///
+ /// Writes a 7-bit encoded integer from the stream. This is stored with the least significant
+ /// information first, with 7 bits of information per byte of value, and the top
+ /// bit as a continuation flag.
+ ///
+ /// The 7-bit encoded integer to write to the stream
+ public void Write7BitEncodedInt(int value)
+ {
+ CheckDisposed();
+ if (value < 0)
+ {
+ throw new ArgumentOutOfRangeException("value", "Value must be greater than or equal to 0.");
+ }
+ int index=0;
+ while (value >= 128)
+ {
+ buffer[index++]= (byte)((value&0x7f) | 0x80);
+ value = value >> 7;
+ index++;
+ }
+ buffer[index++]=(byte)value;
+ stream.Write(buffer, 0, index);
+ }
+
+ #endregion
+
+ #region Private methods
+ ///
+ /// Checks whether or not the writer has been disposed, throwing an exception if so.
+ ///
+ void CheckDisposed()
+ {
+ if (disposed)
+ {
+ throw new ObjectDisposedException("EndianBinaryWriter");
+ }
+ }
+
+ ///
+ /// Writes the specified number of bytes from the start of the given byte array,
+ /// after checking whether or not the writer has been disposed.
+ ///
+ /// The array of bytes to write from
+ /// The number of bytes to write
+ void WriteInternal (byte[] bytes, int length)
+ {
+ CheckDisposed();
+ stream.Write(bytes, 0, length);
+ }
+ #endregion
+
+ #region IDisposable Members
+ ///
+ /// Disposes of the underlying stream.
+ ///
+ public void Dispose()
+ {
+ if (!disposed)
+ {
+ Flush();
+ disposed = true;
+ ((IDisposable)stream).Dispose();
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/test/cs/EndianBitConverter.cs b/test/cs/EndianBitConverter.cs
new file mode 100644
index 0000000..aa8774d
--- /dev/null
+++ b/test/cs/EndianBitConverter.cs
@@ -0,0 +1,696 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace MiscUtil.Conversion
+{
+ ///
+ /// Equivalent of System.BitConverter, but with either endianness.
+ ///
+ public abstract class EndianBitConverter
+ {
+ #region Endianness of this converter
+ ///
+ /// Indicates the byte order ("endianess") in which data is converted using this class.
+ ///
+ ///
+ /// Different computer architectures store data using different byte orders. "Big-endian"
+ /// means the most significant byte is on the left end of a word. "Little-endian" means the
+ /// most significant byte is on the right end of a word.
+ ///
+ /// true if this converter is little-endian, false otherwise.
+ public abstract bool IsLittleEndian();
+
+ ///
+ /// Indicates the byte order ("endianess") in which data is converted using this class.
+ ///
+ public abstract Endianness Endianness { get; }
+ #endregion
+
+ #region Factory properties
+ static LittleEndianBitConverter little = new LittleEndianBitConverter();
+ ///
+ /// Returns a little-endian bit converter instance. The same instance is
+ /// always returned.
+ ///
+ public static LittleEndianBitConverter Little
+ {
+ get { return little; }
+ }
+
+ static BigEndianBitConverter big = new BigEndianBitConverter();
+ ///
+ /// Returns a big-endian bit converter instance. The same instance is
+ /// always returned.
+ ///
+ public static BigEndianBitConverter Big
+ {
+ get { return big; }
+ }
+ #endregion
+
+ #region Double/primitive conversions
+ ///
+ /// Converts the specified double-precision floating point number to a
+ /// 64-bit signed integer. Note: the endianness of this converter does not
+ /// affect the returned value.
+ ///
+ /// The number to convert.
+ /// A 64-bit signed integer whose value is equivalent to value.
+ public long DoubleToInt64Bits(double value)
+ {
+ return BitConverter.DoubleToInt64Bits(value);
+ }
+
+ ///
+ /// Converts the specified 64-bit signed integer to a double-precision
+ /// floating point number. Note: the endianness of this converter does not
+ /// affect the returned value.
+ ///
+ /// The number to convert.
+ /// A double-precision floating point number whose value is equivalent to value.
+ public double Int64BitsToDouble (long value)
+ {
+ return BitConverter.Int64BitsToDouble(value);
+ }
+
+ ///
+ /// Converts the specified single-precision floating point number to a
+ /// 32-bit signed integer. Note: the endianness of this converter does not
+ /// affect the returned value.
+ ///
+ /// The number to convert.
+ /// A 32-bit signed integer whose value is equivalent to value.
+ public int SingleToInt32Bits(float value)
+ {
+ return new Int32SingleUnion(value).AsInt32;
+ }
+
+ ///
+ /// Converts the specified 32-bit signed integer to a single-precision floating point
+ /// number. Note: the endianness of this converter does not
+ /// affect the returned value.
+ ///
+ /// The number to convert.
+ /// A single-precision floating point number whose value is equivalent to value.
+ public float Int32BitsToSingle (int value)
+ {
+ return new Int32SingleUnion(value).AsSingle;
+ }
+ #endregion
+
+ #region To(PrimitiveType) conversions
+ ///
+ /// Returns a Boolean value converted from one byte at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// true if the byte at startIndex in value is nonzero; otherwise, false.
+ public bool ToBoolean (byte[] value, int startIndex)
+ {
+ CheckByteArgument(value, startIndex, 1);
+ return BitConverter.ToBoolean(value, startIndex);
+ }
+
+ ///
+ /// Returns a Unicode character converted from two bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A character formed by two bytes beginning at startIndex.
+ public char ToChar (byte[] value, int startIndex)
+ {
+ return unchecked((char) (CheckedFromBytes(value, startIndex, 2)));
+ }
+
+ ///
+ /// Returns a double-precision floating point number converted from eight bytes
+ /// at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A double precision floating point number formed by eight bytes beginning at startIndex.
+ public double ToDouble (byte[] value, int startIndex)
+ {
+ return Int64BitsToDouble(ToInt64(value, startIndex));
+ }
+
+ ///
+ /// Returns a single-precision floating point number converted from four bytes
+ /// at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A single precision floating point number formed by four bytes beginning at startIndex.
+ public float ToSingle (byte[] value, int startIndex)
+ {
+ return Int32BitsToSingle(ToInt32(value, startIndex));
+ }
+
+ ///
+ /// Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 16-bit signed integer formed by two bytes beginning at startIndex.
+ public short ToInt16 (byte[] value, int startIndex)
+ {
+ return unchecked((short) (CheckedFromBytes(value, startIndex, 2)));
+ }
+
+ ///
+ /// Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 32-bit signed integer formed by four bytes beginning at startIndex.
+ public int ToInt32 (byte[] value, int startIndex)
+ {
+ return unchecked((int) (CheckedFromBytes(value, startIndex, 4)));
+ }
+
+ ///
+ /// Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 64-bit signed integer formed by eight bytes beginning at startIndex.
+ public long ToInt64 (byte[] value, int startIndex)
+ {
+ return CheckedFromBytes(value, startIndex, 8);
+ }
+
+ ///
+ /// Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 16-bit unsigned integer formed by two bytes beginning at startIndex.
+ public ushort ToUInt16 (byte[] value, int startIndex)
+ {
+ return unchecked((ushort) (CheckedFromBytes(value, startIndex, 2)));
+ }
+
+ ///
+ /// Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 32-bit unsigned integer formed by four bytes beginning at startIndex.
+ public uint ToUInt32 (byte[] value, int startIndex)
+ {
+ return unchecked((uint) (CheckedFromBytes(value, startIndex, 4)));
+ }
+
+ ///
+ /// Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 64-bit unsigned integer formed by eight bytes beginning at startIndex.
+ public ulong ToUInt64 (byte[] value, int startIndex)
+ {
+ return unchecked((ulong) (CheckedFromBytes(value, startIndex, 8)));
+ }
+
+ ///
+ /// Checks the given argument for validity.
+ ///
+ /// The byte array passed in
+ /// The start index passed in
+ /// The number of bytes required
+ /// value is a null reference
+ ///
+ /// startIndex is less than zero or greater than the length of value minus bytesRequired.
+ ///
+ static void CheckByteArgument(byte[] value, int startIndex, int bytesRequired)
+ {
+ if (value==null)
+ {
+ throw new ArgumentNullException("value");
+ }
+ if (startIndex < 0 || startIndex > value.Length-bytesRequired)
+ {
+ throw new ArgumentOutOfRangeException("startIndex");
+ }
+ }
+
+ ///
+ /// Checks the arguments for validity before calling FromBytes
+ /// (which can therefore assume the arguments are valid).
+ ///
+ /// The bytes to convert after checking
+ /// The index of the first byte to convert
+ /// The number of bytes to convert
+ ///
+ long CheckedFromBytes(byte[] value, int startIndex, int bytesToConvert)
+ {
+ CheckByteArgument(value, startIndex, bytesToConvert);
+ return FromBytes(value, startIndex, bytesToConvert);
+ }
+
+ ///
+ /// Convert the given number of bytes from the given array, from the given start
+ /// position, into a long, using the bytes as the least significant part of the long.
+ /// By the time this is called, the arguments have been checked for validity.
+ ///
+ /// The bytes to convert
+ /// The index of the first byte to convert
+ /// The number of bytes to use in the conversion
+ /// The converted number
+ protected abstract long FromBytes(byte[] value, int startIndex, int bytesToConvert);
+ #endregion
+
+ #region ToString conversions
+ ///
+ /// Returns a String converted from the elements of a byte array.
+ ///
+ /// An array of bytes.
+ /// All the elements of value are converted.
+ ///
+ /// A String of hexadecimal pairs separated by hyphens, where each pair
+ /// represents the corresponding element in value; for example, "7F-2C-4A".
+ ///
+ public static string ToString(byte[] value)
+ {
+ return BitConverter.ToString(value);
+ }
+
+ ///
+ /// Returns a String converted from the elements of a byte array starting at a specified array position.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// The elements from array position startIndex to the end of the array are converted.
+ ///
+ /// A String of hexadecimal pairs separated by hyphens, where each pair
+ /// represents the corresponding element in value; for example, "7F-2C-4A".
+ ///
+ public static string ToString(byte[] value, int startIndex)
+ {
+ return BitConverter.ToString(value, startIndex);
+ }
+
+ ///
+ /// Returns a String converted from a specified number of bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// The number of bytes to convert.
+ /// The length elements from array position startIndex are converted.
+ ///
+ /// A String of hexadecimal pairs separated by hyphens, where each pair
+ /// represents the corresponding element in value; for example, "7F-2C-4A".
+ ///
+ public static string ToString(byte[] value, int startIndex, int length)
+ {
+ return BitConverter.ToString(value, startIndex, length);
+ }
+ #endregion
+
+ #region Decimal conversions
+ ///
+ /// Returns a decimal value converted from sixteen bytes
+ /// at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A decimal formed by sixteen bytes beginning at startIndex.
+ public decimal ToDecimal (byte[] value, int startIndex)
+ {
+ // HACK: This always assumes four parts, each in their own endianness,
+ // starting with the first part at the start of the byte array.
+ // On the other hand, there's no real format specified...
+ int[] parts = new int[4];
+ for (int i=0; i < 4; i++)
+ {
+ parts[i] = ToInt32(value, startIndex+i*4);
+ }
+ return new Decimal(parts);
+ }
+
+ ///
+ /// Returns the specified decimal value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 16.
+ public byte[] GetBytes(decimal value)
+ {
+ byte[] bytes = new byte[16];
+ int[] parts = decimal.GetBits(value);
+ for (int i=0; i < 4; i++)
+ {
+ CopyBytesImpl(parts[i], 4, bytes, i*4);
+ }
+ return bytes;
+ }
+
+ ///
+ /// Copies the specified decimal value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// A character to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(decimal value, byte[] buffer, int index)
+ {
+ int[] parts = decimal.GetBits(value);
+ for (int i=0; i < 4; i++)
+ {
+ CopyBytesImpl(parts[i], 4, buffer, i*4+index);
+ }
+ }
+ #endregion
+
+ #region GetBytes conversions
+ ///
+ /// Returns an array with the given number of bytes formed
+ /// from the least significant bytes of the specified value.
+ /// This is used to implement the other GetBytes methods.
+ ///
+ /// The value to get bytes for
+ /// The number of significant bytes to return
+ byte[] GetBytes(long value, int bytes)
+ {
+ byte[] buffer = new byte[bytes];
+ CopyBytes(value, bytes, buffer, 0);
+ return buffer;
+ }
+
+ ///
+ /// Returns the specified Boolean value as an array of bytes.
+ ///
+ /// A Boolean value.
+ /// An array of bytes with length 1.
+ public byte[] GetBytes(bool value)
+ {
+ return BitConverter.GetBytes(value);
+ }
+
+ ///
+ /// Returns the specified Unicode character value as an array of bytes.
+ ///
+ /// A character to convert.
+ /// An array of bytes with length 2.
+ public byte[] GetBytes(char value)
+ {
+ return GetBytes(value, 2);
+ }
+
+ ///
+ /// Returns the specified double-precision floating point value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 8.
+ public byte[] GetBytes(double value)
+ {
+ return GetBytes(DoubleToInt64Bits(value), 8);
+ }
+
+ ///
+ /// Returns the specified 16-bit signed integer value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 2.
+ public byte[] GetBytes(short value)
+ {
+ return GetBytes(value, 2);
+ }
+
+ ///
+ /// Returns the specified 32-bit signed integer value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 4.
+ public byte[] GetBytes(int value)
+ {
+ return GetBytes(value, 4);
+ }
+
+ ///
+ /// Returns the specified 64-bit signed integer value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 8.
+ public byte[] GetBytes(long value)
+ {
+ return GetBytes(value, 8);
+ }
+
+ ///
+ /// Returns the specified single-precision floating point value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 4.
+ public byte[] GetBytes(float value)
+ {
+ return GetBytes(SingleToInt32Bits(value), 4);
+ }
+
+ ///
+ /// Returns the specified 16-bit unsigned integer value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 2.
+ public byte[] GetBytes(ushort value)
+ {
+ return GetBytes(value, 2);
+ }
+
+ ///
+ /// Returns the specified 32-bit unsigned integer value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 4.
+ public byte[] GetBytes(uint value)
+ {
+ return GetBytes(value, 4);
+ }
+
+ ///
+ /// Returns the specified 64-bit unsigned integer value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 8.
+ public byte[] GetBytes(ulong value)
+ {
+ return GetBytes(unchecked((long)value), 8);
+ }
+
+ #endregion
+
+ #region CopyBytes conversions
+ ///
+ /// Copies the given number of bytes from the least-specific
+ /// end of the specified value into the specified byte array, beginning
+ /// at the specified index.
+ /// This is used to implement the other CopyBytes methods.
+ ///
+ /// The value to copy bytes for
+ /// The number of significant bytes to copy
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ void CopyBytes(long value, int bytes, byte[] buffer, int index)
+ {
+ if (buffer==null)
+ {
+ throw new ArgumentNullException("buffer", "Byte array must not be null");
+ }
+ if (buffer.Length < index+bytes)
+ {
+ throw new ArgumentOutOfRangeException("Buffer not big enough for value");
+ }
+ CopyBytesImpl(value, bytes, buffer, index);
+ }
+
+ ///
+ /// Copies the given number of bytes from the least-specific
+ /// end of the specified value into the specified byte array, beginning
+ /// at the specified index.
+ /// This must be implemented in concrete derived classes, but the implementation
+ /// may assume that the value will fit into the buffer.
+ ///
+ /// The value to copy bytes for
+ /// The number of significant bytes to copy
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ protected abstract void CopyBytesImpl(long value, int bytes, byte[] buffer, int index);
+
+ ///
+ /// Copies the specified Boolean value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// A Boolean value.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(bool value, byte[] buffer, int index)
+ {
+ CopyBytes(value ? 1 : 0, 1, buffer, index);
+ }
+
+ ///
+ /// Copies the specified Unicode character value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// A character to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(char value, byte[] buffer, int index)
+ {
+ CopyBytes(value, 2, buffer, index);
+ }
+
+ ///
+ /// Copies the specified double-precision floating point value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(double value, byte[] buffer, int index)
+ {
+ CopyBytes(DoubleToInt64Bits(value), 8, buffer, index);
+ }
+
+ ///
+ /// Copies the specified 16-bit signed integer value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(short value, byte[] buffer, int index)
+ {
+ CopyBytes(value, 2, buffer, index);
+ }
+
+ ///
+ /// Copies the specified 32-bit signed integer value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(int value, byte[] buffer, int index)
+ {
+ CopyBytes(value, 4, buffer, index);
+ }
+
+ ///
+ /// Copies the specified 64-bit signed integer value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(long value, byte[] buffer, int index)
+ {
+ CopyBytes(value, 8, buffer, index);
+ }
+
+ ///
+ /// Copies the specified single-precision floating point value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(float value, byte[] buffer, int index)
+ {
+ CopyBytes(SingleToInt32Bits(value), 4, buffer, index);
+ }
+
+ ///
+ /// Copies the specified 16-bit unsigned integer value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(ushort value, byte[] buffer, int index)
+ {
+ CopyBytes(value, 2, buffer, index);
+ }
+
+ ///
+ /// Copies the specified 32-bit unsigned integer value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(uint value, byte[] buffer, int index)
+ {
+ CopyBytes(value, 4, buffer, index);
+ }
+
+ ///
+ /// Copies the specified 64-bit unsigned integer value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(ulong value, byte[] buffer, int index)
+ {
+ CopyBytes(unchecked((long)value), 8, buffer, index);
+ }
+
+ #endregion
+
+ #region Private struct used for Single/Int32 conversions
+ ///
+ /// Union used solely for the equivalent of DoubleToInt64Bits and vice versa.
+ ///
+ [StructLayout(LayoutKind.Explicit)]
+ struct Int32SingleUnion
+ {
+ ///
+ /// Int32 version of the value.
+ ///
+ [FieldOffset(0)]
+ int i;
+ ///
+ /// Single version of the value.
+ ///
+ [FieldOffset(0)]
+ float f;
+
+ ///
+ /// Creates an instance representing the given integer.
+ ///
+ /// The integer value of the new instance.
+ internal Int32SingleUnion(int i)
+ {
+ this.f = 0; // Just to keep the compiler happy
+ this.i = i;
+ }
+
+ ///
+ /// Creates an instance representing the given floating point number.
+ ///
+ /// The floating point value of the new instance.
+ internal Int32SingleUnion(float f)
+ {
+ this.i = 0; // Just to keep the compiler happy
+ this.f = f;
+ }
+
+ ///
+ /// Returns the value of the instance as an integer.
+ ///
+ internal int AsInt32
+ {
+ get { return i; }
+ }
+
+ ///
+ /// Returns the value of the instance as a floating point number.
+ ///
+ internal float AsSingle
+ {
+ get { return f; }
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/test/cs/Endianness.cs b/test/cs/Endianness.cs
new file mode 100644
index 0000000..d8bd5e5
--- /dev/null
+++ b/test/cs/Endianness.cs
@@ -0,0 +1,17 @@
+namespace MiscUtil.Conversion
+{
+ ///
+ /// Endianness of a converter
+ ///
+ public enum Endianness
+ {
+ ///
+ /// Little endian - least significant byte first
+ ///
+ LittleEndian,
+ ///
+ /// Big endian - most significant byte first
+ ///
+ BigEndian
+ }
+}
\ No newline at end of file
diff --git a/test/cs/LittleEndianBitConverter.cs b/test/cs/LittleEndianBitConverter.cs
new file mode 100644
index 0000000..374bbb3
--- /dev/null
+++ b/test/cs/LittleEndianBitConverter.cs
@@ -0,0 +1,66 @@
+
+namespace MiscUtil.Conversion
+{
+ ///
+ /// Implementation of EndianBitConverter which converts to/from little-endian
+ /// byte arrays.
+ ///
+ public sealed class LittleEndianBitConverter : EndianBitConverter
+ {
+ ///
+ /// Indicates the byte order ("endianess") in which data is converted using this class.
+ ///
+ ///
+ /// Different computer architectures store data using different byte orders. "Big-endian"
+ /// means the most significant byte is on the left end of a word. "Little-endian" means the
+ /// most significant byte is on the right end of a word.
+ ///
+ /// true if this converter is little-endian, false otherwise.
+ public sealed override bool IsLittleEndian()
+ {
+ return true;
+ }
+
+ ///
+ /// Indicates the byte order ("endianess") in which data is converted using this class.
+ ///
+ public sealed override Endianness Endianness
+ {
+ get { return Endianness.LittleEndian; }
+ }
+
+ ///
+ /// Copies the specified number of bytes from value to buffer, starting at index.
+ ///
+ /// The value to copy
+ /// The number of bytes to copy
+ /// The buffer to copy the bytes into
+ /// The index to start at
+ protected override void CopyBytesImpl(long value, int bytes, byte[] buffer, int index)
+ {
+ for (int i=0; i < bytes; i++)
+ {
+ buffer[i+index] = unchecked((byte)(value&0xff));
+ value = value >> 8;
+ }
+ }
+
+ ///
+ /// Returns a value built from the specified number of bytes from the given buffer,
+ /// starting at index.
+ ///
+ /// The data in byte array format
+ /// The first index to use
+ /// The number of bytes to use
+ /// The value built from the given bytes
+ protected override long FromBytes(byte[] buffer, int startIndex, int bytesToConvert)
+ {
+ long ret = 0;
+ for (int i=0; i < bytesToConvert; i++)
+ {
+ ret = unchecked((ret << 8) | buffer[startIndex+bytesToConvert-1-i]);
+ }
+ return ret;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/cs/ProtoTest.cs b/test/cs/ProtoTest.cs
new file mode 100644
index 0000000..5adac72
--- /dev/null
+++ b/test/cs/ProtoTest.cs
@@ -0,0 +1,14 @@
+using GenProto;
+
+phoneNumber phoneNumber = new phoneNumber()
+{
+ number = new test { aa = "hello" },
+ type = 100
+};
+
+var data = phoneNumber.Serialize();
+
+var ss = new phoneNumber();
+ss.Deserialize(data);
+
+Console.WriteLine("Hello, World!");
\ No newline at end of file
diff --git a/test/protoMsg.cs b/test/cs/protoMsg.cs
similarity index 100%
rename from test/protoMsg.cs
rename to test/cs/protoMsg.cs
diff --git a/test/v1/protoMsg.erl b/test/erl/erlv1/protoMsg.erl
similarity index 100%
rename from test/v1/protoMsg.erl
rename to test/erl/erlv1/protoMsg.erl
diff --git a/test/v1/protoMsg.hrl b/test/erl/erlv1/protoMsg.hrl
similarity index 100%
rename from test/v1/protoMsg.hrl
rename to test/erl/erlv1/protoMsg.hrl
diff --git a/test/v1/test.erl b/test/erl/erlv1/protoTest.erl
similarity index 99%
rename from test/v1/test.erl
rename to test/erl/erlv1/protoTest.erl
index ba835cd..dcd8c13 100644
--- a/test/v1/test.erl
+++ b/test/erl/erlv1/protoTest.erl
@@ -1,4 +1,4 @@
--module(test).
+-module(protoTest).
-include("protoMsg.hrl").
-compile(export_all).
diff --git a/test/start.bat b/test/erl/erlv1/start.bat
similarity index 100%
rename from test/start.bat
rename to test/erl/erlv1/start.bat
diff --git a/test/protoMsg.erl b/test/erl/protoMsg.erl
similarity index 100%
rename from test/protoMsg.erl
rename to test/erl/protoMsg.erl
diff --git a/test/protoMsg.hrl b/test/erl/protoMsg.hrl
similarity index 100%
rename from test/protoMsg.hrl
rename to test/erl/protoMsg.hrl
diff --git a/test/test.erl b/test/erl/protoTest.erl
similarity index 99%
rename from test/test.erl
rename to test/erl/protoTest.erl
index b5a13e1..0178d0d 100644
--- a/test/test.erl
+++ b/test/erl/protoTest.erl
@@ -1,6 +1,6 @@
--module(test).
+-module(protoTest).
--include("protoMsg.hrl").
+-include("../erl/protoMsg.hrl").
-compile(export_all).
encode_int32(N) ->
diff --git a/test/remake.bat b/test/erl/remake.bat
similarity index 100%
rename from test/remake.bat
rename to test/erl/remake.bat
diff --git a/test/remake.sh b/test/erl/remake.sh
similarity index 100%
rename from test/remake.sh
rename to test/erl/remake.sh
diff --git a/test/gen.bat b/test/gen.bat
index ccae33e..88e804d 100644
--- a/test/gen.bat
+++ b/test/gen.bat
@@ -1 +1 @@
-genProto ../proto ./ ./
+genProto ../proto erl ./erl ./erl lua ./lua cs ./cs
diff --git a/test/gen.sh b/test/gen.sh
index ccae33e..88e804d 100644
--- a/test/gen.sh
+++ b/test/gen.sh
@@ -1 +1 @@
-genProto ../proto ./ ./
+genProto ../proto erl ./erl ./erl lua ./lua cs ./cs
diff --git a/test/genProto b/test/genProto
deleted file mode 100644
index 6f34fff..0000000
Binary files a/test/genProto and /dev/null differ
diff --git a/test/genProto.cmd b/test/genProto.cmd
deleted file mode 100644
index 179789b..0000000
--- a/test/genProto.cmd
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-escript.exe "%~dpn0" %*
diff --git a/test/lua/ByteArray.lua b/test/lua/ByteArray.lua
new file mode 100644
index 0000000..076fc09
--- /dev/null
+++ b/test/lua/ByteArray.lua
@@ -0,0 +1,251 @@
+function ByteArray(endian)
+ local mRadix = {[8]="%03o", [10]="%03u", [16]="%02X"} -- 进制
+ local mBuf = {} -- 二进制字节流
+ local mPos = 1 -- 读写位置
+ -- 验证读写位置
+ local function checkAvailable()
+ assert(#mBuf >= mPos, string.format("End of file was encountered. pos: %d, length: %d.", mPos, #mBuf))
+ end
+ -- 获取字符码
+ local function getLetterCode(fmt)
+ fmt = fmt or ""
+ return ">"..fmt
+ end
+ -- 读单个字节
+ local function readRawByte()
+ checkAvailable()
+ local rawByte = mBuf[mPos]
+ mPos = mPos + 1
+ return rawByte
+ end
+ -- 写单个字节
+ local function writeRawByte(rawByte)
+ if mPos > #mBuf + 1 then
+ for i=#mBuf + 1, mPos - 1 do
+ mBuf[i] = string.char(0)
+ end
+ end
+ mBuf[mPos] = rawByte
+ mPos = mPos + 1
+ end
+ -- 读字节流
+ local function readBuf(length)
+ checkAvailable()
+ local buf = table.concat(mBuf, "", mPos, mPos + length - 1)
+ mPos = mPos + length
+ return buf
+ end
+ -- 写字节流
+ local function writeBuf(buf)
+ for i=1, #buf do
+ writeRawByte(buf:sub(i, i))
+ end
+ end
+ -- 读字符串
+ local function read_string_bytes(length)
+ if 0 == length then
+ return ""
+ end
+ local tmp, value = string.unpack(readBuf(length), getLetterCode("A"..length))
+ return value
+ end
+ -- 写字符串
+ local function write_string_bytes(value)
+ local buf = string.pack(getLetterCode("A"), value)
+ writeBuf(buf)
+ end
+ ----------------------------------------------------------------------
+ -- public method
+ ----------------------------------------------------------------------
+ local ba = {}
+ -- 设置字节流
+ ba.setBytes = function(buf)
+ if #mBuf > 0 then
+ return
+ end
+ writeBuf(buf)
+ mPos = 1 -- 这里必须重置读写位置为1,方能保证接下去的读操作正确
+ end
+ -- 获取字节流
+ ba.getBytes = function()
+ local bytes = {}
+ for i=1, #mBuf do
+ bytes[#bytes+1] = string.byte(mBuf[i])
+ end
+ local packRes = string.pack(getLetterCode("b"..#bytes), unpack(bytes))
+ return packRes
+ end
+ -- 获取字节流长度
+ ba.getLength = function()
+ return #mBuf
+ end
+ -- 字节流转为字符串,radix-8,10,16
+ ba.toString = function(radix, separator)
+ radix = radix or 16
+ radix = mRadix[radix] or "%02X"
+ separator = separator or " "
+ local bytes = {}
+ for i=1, #mBuf do
+ bytes[i] = string.format(radix..separator, string.byte(mBuf[i]))
+ end
+ return table.concat(bytes)
+ end
+ ----------------------------------------------------------------------
+ -- 读16位整型
+ ba.read_int16 = function()
+ local tmp, value = string.unpack(readBuf(2), getLetterCode("h"))
+ return value
+ end
+ -- 写16位整型
+ ba.write_int16 = function(value)
+ local buf = string.pack(getLetterCode("h"), value)
+ writeBuf(buf)
+ end
+ -- 读16位无符号整型
+ ba.read_uint16 = function()
+ local tmp, value = string.unpack(readBuf(2), getLetterCode("H"))
+ return value
+ end
+ -- 写16位无符号整型
+ ba.write_uint16 = function(value)
+ local sstr = getLetterCode("H")
+ local buf = string.pack(sstr, value)
+ writeBuf(buf)
+ end
+ -- 读32位整型
+ ba.read_int32 = function()
+ local tmp, value = string.unpack(readBuf(4), getLetterCode("i"))
+ return value
+ end
+ -- 写32位整型
+ ba.write_int32 = function(value)
+ local buf = string.pack(getLetterCode("i"), value)
+ writeBuf(buf)
+ end
+ -- 读32位无符号整型
+ ba.read_uint32 = function()
+ local tmp, value = string.unpack(readBuf(4), getLetterCode("I"))
+ return value
+ end
+ -- 写32位无符号整型
+ ba.write_uint32 = function(value)
+ local buf = string.pack(getLetterCode("I"), value)
+ writeBuf(buf)
+ end
+ -- 读长整型
+ ba.read_long = function()
+ local tmp, value = string.unpack(readBuf(4), getLetterCode("l"))
+ return value
+ end
+ -- 写长整型
+ ba.write_long = function(value)
+ local buf = string.pack(getLetterCode("l"), value)
+ writeBuf(buf)
+ end
+ -- 读无符号长整型
+ ba.read_ulong = function()
+ local tmp, value = string.unpack(readBuf(4), getLetterCode("L"))
+ return value
+ end
+ -- 写无符号长整型
+ ba.write_ulong = function(value)
+ local buf = string.pack(getLetterCode("L"), value)
+ writeBuf(buf)
+ end
+ -- 读64位整型
+ ba.read_int64 = function()
+ -- local tmp, value = string.unpack(readBuf(8), getLetterCode("m"))
+ -- return value
+ return read_string_bytes(8)
+ end
+ -- 写64位整型
+ ba.write_int64 = function(value)
+ -- local buf = string.pack(getLetterCode("m"), value)
+ -- writeBuf(buf)
+ local buf = string.pack(getLetterCode("A"), value)
+ writeBuf(buf)
+ end
+ -- 读64位无符号整型
+ ba.read_uint64 = function()
+ -- local tmp, value = string.unpack(readBuf(8), getLetterCode("M"))
+ -- return value
+ return read_string_bytes(8)
+ end
+ -- 写64位无符号整型
+ ba.write_uint64 = function(value)
+ -- local buf = string.pack(getLetterCode("M"), value)
+ -- writeBuf(buf)
+ local buf = string.pack(getLetterCode("A"), value)
+ writeBuf(buf)
+ end
+ -- 读单精度浮点型
+ ba.read_float = function()
+ local tmp, value = string.unpack(readBuf(4), getLetterCode("f"))
+ return value
+ end
+ -- 写单精度浮点型
+ ba.write_float = function(value)
+ local buf = string.pack(getLetterCode("f"), value)
+ writeBuf(buf)
+ end
+ -- 读双精度浮点型
+ ba.read_double = function()
+ local tmp, value = string.unpack(readBuf(8), getLetterCode("d"))
+ return value
+ end
+ -- 写双精度浮点型
+ ba.write_double = function(value)
+ local buf = string.pack(getLetterCode("d"), value)
+ writeBuf(buf)
+ end
+ -- 读布尔型
+ ba.read_bool = function()
+ return 1 == read_char()
+ end
+ -- 写布尔型
+ ba.write_bool = function(value)
+ if value then
+ ba.write_char(1)
+ else
+ ba.write_char(0)
+ end
+ end
+ -- 读字符型
+ ba.read_int8 = function()
+ local tmp, value = string.unpack(readRawByte(), "c")
+ return value
+ end
+ -- 写字符型
+ ba.write_int8 = function(value)
+ writeRawByte(string.pack("c", value))
+ end
+ -- 读单字节
+ ba.read_uint8 = function()
+ -- 方法1
+ -- return string.byte(readRawByte())
+ -- 方法2
+ local tmp, value = string.unpack(readRawByte(), "b")
+ return value
+ end
+ -- 写单字节
+ ba.write_uint8 = function(value)
+ -- 方法1
+ -- writeRawByte(string.char(value))
+ -- 方法2
+ writeRawByte(string.pack("b", value))
+ end
+ -- 读字符串
+ ba.read_string = function()
+ local length = ba.read_uint16()
+ return read_string_bytes(length)
+ end
+ -- 写字符串
+ ba.write_string = function(value)
+ local buf = string.pack(getLetterCode("A"), value)
+ ba.write_uint16(#buf)
+ writeBuf(buf)
+ end
+ ----------------------------------------------------------------------
+ return ba
+end
+
diff --git a/src/writeLua/ByteArray.lua b/test/lua/ByteArray_back.lua
similarity index 100%
rename from src/writeLua/ByteArray.lua
rename to test/lua/ByteArray_back.lua
diff --git a/test/protoMsg.lua b/test/lua/protoMsg.lua
similarity index 100%
rename from test/protoMsg.lua
rename to test/lua/protoMsg.lua
diff --git a/test/protoName.lua b/test/lua/protoName.lua
similarity index 100%
rename from test/protoName.lua
rename to test/lua/protoName.lua
diff --git a/test/lua/protoTest.lua b/test/lua/protoTest.lua
new file mode 100644
index 0000000..c13cdc3
--- /dev/null
+++ b/test/lua/protoTest.lua
@@ -0,0 +1,19 @@
+function test()
+ -- 封包
+
+ local msgTable = new phoneNumber()
+ msgTable.number = new test()
+ msgTable.type = 1
+ local byteArray = ByteArray()
+ byteArray = msgTable.build(byteArray)
+ local body = byteArray.getBytes()
+ -- 包头(大小端转换后的包体长度)
+ local bodyLength = string.len(body) -- 包体长度
+ local head = string.pack(">I4", bodyLength) -- 包头四个字节,这里要用"i"
+ -- 发送
+ local nSend = dosend(head..body)
+
+ -- 解包 先读取消息id 根据消息id到protoNane.lua 获取函数名
+ -- 再根据函数名到 _G表找到反序列化的函数
+
+end
\ No newline at end of file
diff --git a/test/v1/start.bat b/test/v1/start.bat
deleted file mode 100644
index 59d0635..0000000
--- a/test/v1/start.bat
+++ /dev/null
@@ -1 +0,0 @@
-start werl.exe
\ No newline at end of file