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