Browse Source

ft: 目录结构调整

master
SisMaker 1 year ago
parent
commit
075846652f
30 changed files with 2138 additions and 10 deletions
  1. BIN
      genProto
  2. +0
    -2
      genProto.cmd
  3. +67
    -0
      test/cs/BigEndianBitConverter.cs
  4. +12
    -0
      test/cs/ConsoleApp2.csproj
  5. +599
    -0
      test/cs/EndianBinaryReader.cs
  6. +392
    -0
      test/cs/EndianBinaryWriter.cs
  7. +696
    -0
      test/cs/EndianBitConverter.cs
  8. +17
    -0
      test/cs/Endianness.cs
  9. +66
    -0
      test/cs/LittleEndianBitConverter.cs
  10. +14
    -0
      test/cs/ProtoTest.cs
  11. +0
    -0
      test/cs/protoMsg.cs
  12. +0
    -0
      test/erl/erlv1/protoMsg.erl
  13. +0
    -0
      test/erl/erlv1/protoMsg.hrl
  14. +1
    -1
      test/erl/erlv1/protoTest.erl
  15. +0
    -0
      test/erl/erlv1/start.bat
  16. +0
    -0
      test/erl/protoMsg.erl
  17. +0
    -0
      test/erl/protoMsg.hrl
  18. +2
    -2
      test/erl/protoTest.erl
  19. +0
    -0
      test/erl/remake.bat
  20. +0
    -0
      test/erl/remake.sh
  21. +1
    -1
      test/gen.bat
  22. +1
    -1
      test/gen.sh
  23. BIN
      test/genProto
  24. +0
    -2
      test/genProto.cmd
  25. +251
    -0
      test/lua/ByteArray.lua
  26. +0
    -0
      test/lua/ByteArray_back.lua
  27. +0
    -0
      test/lua/protoMsg.lua
  28. +0
    -0
      test/lua/protoName.lua
  29. +19
    -0
      test/lua/protoTest.lua
  30. +0
    -1
      test/v1/start.bat

BIN
genProto View File


+ 0
- 2
genProto.cmd View File

@ -1,2 +0,0 @@
@echo off
escript.exe "%~dpn0" %*

+ 67
- 0
test/cs/BigEndianBitConverter.cs View File

@ -0,0 +1,67 @@

namespace MiscUtil.Conversion
{
/// <summary>
/// Implementation of EndianBitConverter which converts to/from big-endian
/// byte arrays.
/// </summary>
public sealed class BigEndianBitConverter : EndianBitConverter
{
/// <summary>
/// Indicates the byte order ("endianess") in which data is converted using this class.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
/// <returns>true if this converter is little-endian, false otherwise.</returns>
public sealed override bool IsLittleEndian()
{
return false;
}
/// <summary>
/// Indicates the byte order ("endianess") in which data is converted using this class.
/// </summary>
public sealed override Endianness Endianness
{
get { return Endianness.BigEndian; }
}
/// <summary>
/// Copies the specified number of bytes from value to buffer, starting at index.
/// </summary>
/// <param name="value">The value to copy</param>
/// <param name="bytes">The number of bytes to copy</param>
/// <param name="buffer">The buffer to copy the bytes into</param>
/// <param name="index">The index to start at</param>
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;
}
}
/// <summary>
/// Returns a value built from the specified number of bytes from the given buffer,
/// starting at index.
/// </summary>
/// <param name="buffer">The data in byte array format</param>
/// <param name="startIndex">The first index to use</param>
/// <param name="bytesToConvert">The number of bytes to use</param>
/// <returns>The value built from the given bytes</returns>
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;
}
}
}

+ 12
- 0
test/cs/ConsoleApp2.csproj View File

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

+ 599
- 0
test/cs/EndianBinaryReader.cs View File

@ -0,0 +1,599 @@
using System;
using System.IO;
using System.Text;
using MiscUtil.Conversion;
namespace MiscUtil.IO
{
/// <summary>
/// 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.
/// </summary>
public class EndianBinaryReader : IDisposable
{
#region Fields not directly related to properties
/// <summary>
/// Whether or not this reader has been disposed yet.
/// </summary>
bool disposed=false;
/// <summary>
/// Decoder to use for string conversions.
/// </summary>
Decoder decoder;
/// <summary>
/// Buffer used for temporary storage before conversion into primitives
/// </summary>
byte[] buffer = new byte[16];
/// <summary>
/// Buffer used for temporary storage when reading a single character
/// </summary>
char[] charBuffer = new char[1];
/// <summary>
/// Minimum number of bytes used to encode a character
/// </summary>
int minBytesPerChar;
#endregion
#region Constructors
/// <summary>
/// Equivalent of System.IO.BinaryWriter, but with either endianness, depending on
/// the EndianBitConverter it is constructed with.
/// </summary>
/// <param name="bitConverter">Converter to use when reading data</param>
/// <param name="stream">Stream to read data from</param>
public EndianBinaryReader (EndianBitConverter bitConverter,
Stream stream) : this (bitConverter, stream, Encoding.UTF8)
{
}
/// <summary>
/// Constructs a new binary reader with the given bit converter, reading
/// to the given stream, using the given encoding.
/// </summary>
/// <param name="bitConverter">Converter to use when reading data</param>
/// <param name="stream">Stream to read data from</param>
/// <param name="encoding">Encoding to use when reading character data</param>
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;
/// <summary>
/// The bit converter used to read values from the stream
/// </summary>
public EndianBitConverter BitConverter
{
get { return bitConverter; }
}
Encoding encoding;
/// <summary>
/// The encoding used to read strings
/// </summary>
public Encoding Encoding
{
get { return encoding; }
}
Stream stream;
/// <summary>
/// Gets the underlying stream of the EndianBinaryReader.
/// </summary>
public Stream BaseStream
{
get { return stream; }
}
#endregion
#region Public methods
/// <summary>
/// Closes the reader, including the underlying stream..
/// </summary>
public void Close()
{
Dispose();
}
/// <summary>
/// Seeks within the stream.
/// </summary>
/// <param name="offset">Offset to seek to.</param>
/// <param name="origin">Origin of seek operation.</param>
public void Seek (int offset, SeekOrigin origin)
{
CheckDisposed();
stream.Seek (offset, origin);
}
/// <summary>
/// Reads a single byte from the stream.
/// </summary>
/// <returns>The byte read</returns>
public byte ReadByte()
{
ReadInternal(buffer, 1);
return buffer[0];
}
/// <summary>
/// Reads a single signed byte from the stream.
/// </summary>
/// <returns>The byte read</returns>
public sbyte ReadSByte()
{
ReadInternal(buffer, 1);
return unchecked((sbyte)buffer[0]);
}
/// <summary>
/// Reads a boolean from the stream. 1 byte is read.
/// </summary>
/// <returns>The boolean read</returns>
public bool ReadBoolean()
{
ReadInternal(buffer, 1);
return bitConverter.ToBoolean(buffer, 0);
}
/// <summary>
/// Reads a 16-bit signed integer from the stream, using the bit converter
/// for this reader. 2 bytes are read.
/// </summary>
/// <returns>The 16-bit integer read</returns>
public short ReadInt16()
{
ReadInternal(buffer, 2);
return bitConverter.ToInt16(buffer, 0);
}
/// <summary>
/// Reads a 32-bit signed integer from the stream, using the bit converter
/// for this reader. 4 bytes are read.
/// </summary>
/// <returns>The 32-bit integer read</returns>
public int ReadInt32()
{
ReadInternal(buffer, 4);
return bitConverter.ToInt32(buffer, 0);
}
/// <summary>
/// Reads a 64-bit signed integer from the stream, using the bit converter
/// for this reader. 8 bytes are read.
/// </summary>
/// <returns>The 64-bit integer read</returns>
public long ReadInt64()
{
ReadInternal(buffer, 8);
return bitConverter.ToInt64(buffer, 0);
}
/// <summary>
/// Reads a 16-bit unsigned integer from the stream, using the bit converter
/// for this reader. 2 bytes are read.
/// </summary>
/// <returns>The 16-bit unsigned integer read</returns>
public ushort ReadUInt16()
{
ReadInternal(buffer, 2);
return bitConverter.ToUInt16(buffer, 0);
}
/// <summary>
/// Reads a 32-bit unsigned integer from the stream, using the bit converter
/// for this reader. 4 bytes are read.
/// </summary>
/// <returns>The 32-bit unsigned integer read</returns>
public uint ReadUInt32()
{
ReadInternal(buffer, 4);
return bitConverter.ToUInt32(buffer, 0);
}
/// <summary>
/// Reads a 64-bit unsigned integer from the stream, using the bit converter
/// for this reader. 8 bytes are read.
/// </summary>
/// <returns>The 64-bit unsigned integer read</returns>
public ulong ReadUInt64()
{
ReadInternal(buffer, 8);
return bitConverter.ToUInt64(buffer, 0);
}
/// <summary>
/// Reads a single-precision floating-point value from the stream, using the bit converter
/// for this reader. 4 bytes are read.
/// </summary>
/// <returns>The floating point value read</returns>
public float ReadSingle()
{
ReadInternal(buffer, 4);
return bitConverter.ToSingle(buffer, 0);
}
/// <summary>
/// Reads a double-precision floating-point value from the stream, using the bit converter
/// for this reader. 8 bytes are read.
/// </summary>
/// <returns>The floating point value read</returns>
public double ReadDouble()
{
ReadInternal(buffer, 8);
return bitConverter.ToDouble(buffer, 0);
}
/// <summary>
/// Reads a decimal value from the stream, using the bit converter
/// for this reader. 16 bytes are read.
/// </summary>
/// <returns>The decimal value read</returns>
public decimal ReadDecimal()
{
ReadInternal(buffer, 16);
return bitConverter.ToDecimal(buffer, 0);
}
/// <summary>
/// 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.
/// </summary>
/// <returns>The character read, or -1 for end of stream.</returns>
public int Read()
{
int charsRead = Read(charBuffer, 0, 1);
if (charsRead==0)
{
return -1;
}
else
{
return charBuffer[0];
}
}
/// <summary>
/// Reads the specified number of characters into the given buffer, starting at
/// the given index.
/// </summary>
/// <param name="data">The buffer to copy data into</param>
/// <param name="index">The first index to copy data into</param>
/// <param name="count">The number of characters to read</param>
/// <returns>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.
/// </returns>
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;
}
/// <summary>
/// Reads the specified number of bytes into the given buffer, starting at
/// the given index.
/// </summary>
/// <param name="buffer">The buffer to copy data into</param>
/// <param name="index">The first index to copy data into</param>
/// <param name="count">The number of bytes to read</param>
/// <returns>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.
/// </returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="count">The number of bytes to read</param>
/// <returns>The bytes read</returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="count">The number of bytes to read</param>
/// <returns>The bytes read</returns>
public byte[] ReadBytesOrThrow(int count)
{
byte[] ret = new byte[count];
ReadInternal(ret, count);
return ret;
}
/// <summary>
/// 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.
/// </summary>
/// <returns>The 7-bit encoded integer read from the stream.</returns>
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.");
}
/// <summary>
/// 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.
/// </summary>
/// <returns>The 7-bit encoded integer read from the stream.</returns>
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.");
}
/// <summary>
/// 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.
/// </summary>
/// <returns>The string read from the stream.</returns>
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
/// <summary>
/// Checks whether or not the reader has been disposed, throwing an exception if so.
/// </summary>
void CheckDisposed()
{
if (disposed)
{
throw new ObjectDisposedException("EndianBinaryReader");
}
}
/// <summary>
/// Reads the given number of bytes from the stream, throwing an exception
/// if they can't all be read.
/// </summary>
/// <param name="data">Buffer to read into</param>
/// <param name="size">Number of bytes to read</param>
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;
}
}
/// <summary>
/// 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.
/// </summary>
/// <param name="data">Buffer to read into</param>
/// <param name="size">Number of bytes to read</param>
/// <returns>Number of bytes actually read</returns>
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
/// <summary>
/// Disposes of the underlying stream.
/// </summary>
public void Dispose()
{
if (!disposed)
{
disposed = true;
((IDisposable)stream).Dispose();
}
}
#endregion
}
}

+ 392
- 0
test/cs/EndianBinaryWriter.cs View File

@ -0,0 +1,392 @@
using System;
using System.IO;
using System.Text;
using MiscUtil.Conversion;
namespace MiscUtil.IO
{
/// <summary>
/// Equivalent of System.IO.BinaryWriter, but with either endianness, depending on
/// the EndianBitConverter it is constructed with.
/// </summary>
public class EndianBinaryWriter : IDisposable
{
#region Fields not directly related to properties
/// <summary>
/// Whether or not this writer has been disposed yet.
/// </summary>
bool disposed=false;
/// <summary>
/// Buffer used for temporary storage during conversion from primitives
/// </summary>
byte[] buffer = new byte[16];
/// <summary>
/// Buffer used for Write(char)
/// </summary>
char[] charBuffer = new char[1];
#endregion
#region Constructors
/// <summary>
/// Constructs a new binary writer with the given bit converter, writing
/// to the given stream, using UTF-8 encoding.
/// </summary>
/// <param name="bitConverter">Converter to use when writing data</param>
/// <param name="stream">Stream to write data to</param>
public EndianBinaryWriter (EndianBitConverter bitConverter,
Stream stream) : this (bitConverter, stream, Encoding.UTF8)
{
}
/// <summary>
/// Constructs a new binary writer with the given bit converter, writing
/// to the given stream, using the given encoding.
/// </summary>
/// <param name="bitConverter">Converter to use when writing data</param>
/// <param name="stream">Stream to write data to</param>
/// <param name="encoding">Encoding to use when writing character data</param>
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;
/// <summary>
/// The bit converter used to write values to the stream
/// </summary>
public EndianBitConverter BitConverter
{
get { return bitConverter; }
}
Encoding encoding;
/// <summary>
/// The encoding used to write strings
/// </summary>
public Encoding Encoding
{
get { return encoding; }
}
Stream stream;
/// <summary>
/// Gets the underlying stream of the EndianBinaryWriter.
/// </summary>
public Stream BaseStream
{
get { return stream; }
}
#endregion
#region Public methods
/// <summary>
/// Closes the writer, including the underlying stream.
/// </summary>
public void Close()
{
Dispose();
}
/// <summary>
/// Flushes the underlying stream.
/// </summary>
public void Flush()
{
CheckDisposed();
stream.Flush();
}
/// <summary>
/// Seeks within the stream.
/// </summary>
/// <param name="offset">Offset to seek to.</param>
/// <param name="origin">Origin of seek operation.</param>
public void Seek (int offset, SeekOrigin origin)
{
CheckDisposed();
stream.Seek (offset, origin);
}
/// <summary>
/// Writes a boolean value to the stream. 1 byte is written.
/// </summary>
/// <param name="value">The value to write</param>
public void Write (bool value)
{
bitConverter.CopyBytes(value, buffer, 0);
WriteInternal(buffer, 1);
}
/// <summary>
/// Writes a 16-bit signed integer to the stream, using the bit converter
/// for this writer. 2 bytes are written.
/// </summary>
/// <param name="value">The value to write</param>
public void Write (short value)
{
bitConverter.CopyBytes(value, buffer, 0);
WriteInternal(buffer, 2);
}
/// <summary>
/// Writes a 32-bit signed integer to the stream, using the bit converter
/// for this writer. 4 bytes are written.
/// </summary>
/// <param name="value">The value to write</param>
public void Write (int value)
{
bitConverter.CopyBytes(value, buffer, 0);
WriteInternal(buffer, 4);
}
/// <summary>
/// Writes a 64-bit signed integer to the stream, using the bit converter
/// for this writer. 8 bytes are written.
/// </summary>
/// <param name="value">The value to write</param>
public void Write (long value)
{
bitConverter.CopyBytes(value, buffer, 0);
WriteInternal(buffer, 8);
}
/// <summary>
/// Writes a 16-bit unsigned integer to the stream, using the bit converter
/// for this writer. 2 bytes are written.
/// </summary>
/// <param name="value">The value to write</param>
public void Write (ushort value)
{
bitConverter.CopyBytes(value, buffer, 0);
WriteInternal(buffer, 2);
}
/// <summary>
/// Writes a 32-bit unsigned integer to the stream, using the bit converter
/// for this writer. 4 bytes are written.
/// </summary>
/// <param name="value">The value to write</param>
public void Write (uint value)
{
bitConverter.CopyBytes(value, buffer, 0);
WriteInternal(buffer, 4);
}
/// <summary>
/// Writes a 64-bit unsigned integer to the stream, using the bit converter
/// for this writer. 8 bytes are written.
/// </summary>
/// <param name="value">The value to write</param>
public void Write (ulong value)
{
bitConverter.CopyBytes(value, buffer, 0);
WriteInternal(buffer, 8);
}
/// <summary>
/// Writes a single-precision floating-point value to the stream, using the bit converter
/// for this writer. 4 bytes are written.
/// </summary>
/// <param name="value">The value to write</param>
public void Write (float value)
{
bitConverter.CopyBytes(value, buffer, 0);
WriteInternal(buffer, 4);
}
/// <summary>
/// Writes a double-precision floating-point value to the stream, using the bit converter
/// for this writer. 8 bytes are written.
/// </summary>
/// <param name="value">The value to write</param>
public void Write (double value)
{
bitConverter.CopyBytes(value, buffer, 0);
WriteInternal(buffer, 8);
}
/// <summary>
/// Writes a decimal value to the stream, using the bit converter for this writer.
/// 16 bytes are written.
/// </summary>
/// <param name="value">The value to write</param>
public void Write (decimal value)
{
bitConverter.CopyBytes(value, buffer, 0);
WriteInternal(buffer, 16);
}
/// <summary>
/// Writes a signed byte to the stream.
/// </summary>
/// <param name="value">The value to write</param>
public void Write (byte value)
{
buffer[0] = value;
WriteInternal(buffer, 1);
}
/// <summary>
/// Writes an unsigned byte to the stream.
/// </summary>
/// <param name="value">The value to write</param>
public void Write (sbyte value)
{
buffer[0] = unchecked((byte)value);
WriteInternal(buffer, 1);
}
/// <summary>
/// Writes an array of bytes to the stream.
/// </summary>
/// <param name="value">The values to write</param>
public void Write (byte[] value)
{
if (value == null)
{
throw (new System.ArgumentNullException("value"));
}
WriteInternal(value, value.Length);
}
/// <summary>
/// Writes a portion of an array of bytes to the stream.
/// </summary>
/// <param name="value">An array containing the bytes to write</param>
/// <param name="offset">The index of the first byte to write within the array</param>
/// <param name="count">The number of bytes to write</param>
public void Write (byte[] value, int offset, int count)
{
CheckDisposed();
stream.Write(value, offset, count);
}
/// <summary>
/// Writes a single character to the stream, using the encoding for this writer.
/// </summary>
/// <param name="value">The value to write</param>
public void Write(char value)
{
charBuffer[0] = value;
Write(charBuffer);
}
/// <summary>
/// Writes an array of characters to the stream, using the encoding for this writer.
/// </summary>
/// <param name="value">An array containing the characters to write</param>
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);
}
/// <summary>
/// Writes a string to the stream, using the encoding for this writer.
/// </summary>
/// <param name="value">The value to write. Must not be null.</param>
/// <exception cref="ArgumentNullException">value is null</exception>
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);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="value">The 7-bit encoded integer to write to the stream</param>
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
/// <summary>
/// Checks whether or not the writer has been disposed, throwing an exception if so.
/// </summary>
void CheckDisposed()
{
if (disposed)
{
throw new ObjectDisposedException("EndianBinaryWriter");
}
}
/// <summary>
/// Writes the specified number of bytes from the start of the given byte array,
/// after checking whether or not the writer has been disposed.
/// </summary>
/// <param name="bytes">The array of bytes to write from</param>
/// <param name="length">The number of bytes to write</param>
void WriteInternal (byte[] bytes, int length)
{
CheckDisposed();
stream.Write(bytes, 0, length);
}
#endregion
#region IDisposable Members
/// <summary>
/// Disposes of the underlying stream.
/// </summary>
public void Dispose()
{
if (!disposed)
{
Flush();
disposed = true;
((IDisposable)stream).Dispose();
}
}
#endregion
}
}

+ 696
- 0
test/cs/EndianBitConverter.cs View File

@ -0,0 +1,696 @@
using System;
using System.Runtime.InteropServices;
namespace MiscUtil.Conversion
{
/// <summary>
/// Equivalent of System.BitConverter, but with either endianness.
/// </summary>
public abstract class EndianBitConverter
{
#region Endianness of this converter
/// <summary>
/// Indicates the byte order ("endianess") in which data is converted using this class.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
/// <returns>true if this converter is little-endian, false otherwise.</returns>
public abstract bool IsLittleEndian();
/// <summary>
/// Indicates the byte order ("endianess") in which data is converted using this class.
/// </summary>
public abstract Endianness Endianness { get; }
#endregion
#region Factory properties
static LittleEndianBitConverter little = new LittleEndianBitConverter();
/// <summary>
/// Returns a little-endian bit converter instance. The same instance is
/// always returned.
/// </summary>
public static LittleEndianBitConverter Little
{
get { return little; }
}
static BigEndianBitConverter big = new BigEndianBitConverter();
/// <summary>
/// Returns a big-endian bit converter instance. The same instance is
/// always returned.
/// </summary>
public static BigEndianBitConverter Big
{
get { return big; }
}
#endregion
#region Double/primitive conversions
/// <summary>
/// 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.
/// </summary>
/// <param name="value">The number to convert. </param>
/// <returns>A 64-bit signed integer whose value is equivalent to value.</returns>
public long DoubleToInt64Bits(double value)
{
return BitConverter.DoubleToInt64Bits(value);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="value">The number to convert. </param>
/// <returns>A double-precision floating point number whose value is equivalent to value.</returns>
public double Int64BitsToDouble (long value)
{
return BitConverter.Int64BitsToDouble(value);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="value">The number to convert. </param>
/// <returns>A 32-bit signed integer whose value is equivalent to value.</returns>
public int SingleToInt32Bits(float value)
{
return new Int32SingleUnion(value).AsInt32;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="value">The number to convert. </param>
/// <returns>A single-precision floating point number whose value is equivalent to value.</returns>
public float Int32BitsToSingle (int value)
{
return new Int32SingleUnion(value).AsSingle;
}
#endregion
#region To(PrimitiveType) conversions
/// <summary>
/// Returns a Boolean value converted from one byte at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>true if the byte at startIndex in value is nonzero; otherwise, false.</returns>
public bool ToBoolean (byte[] value, int startIndex)
{
CheckByteArgument(value, startIndex, 1);
return BitConverter.ToBoolean(value, startIndex);
}
/// <summary>
/// Returns a Unicode character converted from two bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A character formed by two bytes beginning at startIndex.</returns>
public char ToChar (byte[] value, int startIndex)
{
return unchecked((char) (CheckedFromBytes(value, startIndex, 2)));
}
/// <summary>
/// Returns a double-precision floating point number converted from eight bytes
/// at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A double precision floating point number formed by eight bytes beginning at startIndex.</returns>
public double ToDouble (byte[] value, int startIndex)
{
return Int64BitsToDouble(ToInt64(value, startIndex));
}
/// <summary>
/// Returns a single-precision floating point number converted from four bytes
/// at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A single precision floating point number formed by four bytes beginning at startIndex.</returns>
public float ToSingle (byte[] value, int startIndex)
{
return Int32BitsToSingle(ToInt32(value, startIndex));
}
/// <summary>
/// Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 16-bit signed integer formed by two bytes beginning at startIndex.</returns>
public short ToInt16 (byte[] value, int startIndex)
{
return unchecked((short) (CheckedFromBytes(value, startIndex, 2)));
}
/// <summary>
/// Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 32-bit signed integer formed by four bytes beginning at startIndex.</returns>
public int ToInt32 (byte[] value, int startIndex)
{
return unchecked((int) (CheckedFromBytes(value, startIndex, 4)));
}
/// <summary>
/// Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 64-bit signed integer formed by eight bytes beginning at startIndex.</returns>
public long ToInt64 (byte[] value, int startIndex)
{
return CheckedFromBytes(value, startIndex, 8);
}
/// <summary>
/// Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 16-bit unsigned integer formed by two bytes beginning at startIndex.</returns>
public ushort ToUInt16 (byte[] value, int startIndex)
{
return unchecked((ushort) (CheckedFromBytes(value, startIndex, 2)));
}
/// <summary>
/// Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 32-bit unsigned integer formed by four bytes beginning at startIndex.</returns>
public uint ToUInt32 (byte[] value, int startIndex)
{
return unchecked((uint) (CheckedFromBytes(value, startIndex, 4)));
}
/// <summary>
/// Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 64-bit unsigned integer formed by eight bytes beginning at startIndex.</returns>
public ulong ToUInt64 (byte[] value, int startIndex)
{
return unchecked((ulong) (CheckedFromBytes(value, startIndex, 8)));
}
/// <summary>
/// Checks the given argument for validity.
/// </summary>
/// <param name="value">The byte array passed in</param>
/// <param name="startIndex">The start index passed in</param>
/// <param name="bytesRequired">The number of bytes required</param>
/// <exception cref="ArgumentNullException">value is a null reference</exception>
/// <exception cref="ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value minus bytesRequired.
/// </exception>
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");
}
}
/// <summary>
/// Checks the arguments for validity before calling FromBytes
/// (which can therefore assume the arguments are valid).
/// </summary>
/// <param name="value">The bytes to convert after checking</param>
/// <param name="startIndex">The index of the first byte to convert</param>
/// <param name="bytesToConvert">The number of bytes to convert</param>
/// <returns></returns>
long CheckedFromBytes(byte[] value, int startIndex, int bytesToConvert)
{
CheckByteArgument(value, startIndex, bytesToConvert);
return FromBytes(value, startIndex, bytesToConvert);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="value">The bytes to convert</param>
/// <param name="startIndex">The index of the first byte to convert</param>
/// <param name="bytesToConvert">The number of bytes to use in the conversion</param>
/// <returns>The converted number</returns>
protected abstract long FromBytes(byte[] value, int startIndex, int bytesToConvert);
#endregion
#region ToString conversions
/// <summary>
/// Returns a String converted from the elements of a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <remarks>All the elements of value are converted.</remarks>
/// <returns>
/// A String of hexadecimal pairs separated by hyphens, where each pair
/// represents the corresponding element in value; for example, "7F-2C-4A".
/// </returns>
public static string ToString(byte[] value)
{
return BitConverter.ToString(value);
}
/// <summary>
/// Returns a String converted from the elements of a byte array starting at a specified array position.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <remarks>The elements from array position startIndex to the end of the array are converted.</remarks>
/// <returns>
/// A String of hexadecimal pairs separated by hyphens, where each pair
/// represents the corresponding element in value; for example, "7F-2C-4A".
/// </returns>
public static string ToString(byte[] value, int startIndex)
{
return BitConverter.ToString(value, startIndex);
}
/// <summary>
/// Returns a String converted from a specified number of bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <param name="length">The number of bytes to convert.</param>
/// <remarks>The length elements from array position startIndex are converted.</remarks>
/// <returns>
/// A String of hexadecimal pairs separated by hyphens, where each pair
/// represents the corresponding element in value; for example, "7F-2C-4A".
/// </returns>
public static string ToString(byte[] value, int startIndex, int length)
{
return BitConverter.ToString(value, startIndex, length);
}
#endregion
#region Decimal conversions
/// <summary>
/// Returns a decimal value converted from sixteen bytes
/// at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A decimal formed by sixteen bytes beginning at startIndex.</returns>
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);
}
/// <summary>
/// Returns the specified decimal value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 16.</returns>
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;
}
/// <summary>
/// Copies the specified decimal value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">A character to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
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
/// <summary>
/// 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.
/// </summary>
/// <param name="value">The value to get bytes for</param>
/// <param name="bytes">The number of significant bytes to return</param>
byte[] GetBytes(long value, int bytes)
{
byte[] buffer = new byte[bytes];
CopyBytes(value, bytes, buffer, 0);
return buffer;
}
/// <summary>
/// Returns the specified Boolean value as an array of bytes.
/// </summary>
/// <param name="value">A Boolean value.</param>
/// <returns>An array of bytes with length 1.</returns>
public byte[] GetBytes(bool value)
{
return BitConverter.GetBytes(value);
}
/// <summary>
/// Returns the specified Unicode character value as an array of bytes.
/// </summary>
/// <param name="value">A character to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
public byte[] GetBytes(char value)
{
return GetBytes(value, 2);
}
/// <summary>
/// Returns the specified double-precision floating point value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public byte[] GetBytes(double value)
{
return GetBytes(DoubleToInt64Bits(value), 8);
}
/// <summary>
/// Returns the specified 16-bit signed integer value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
public byte[] GetBytes(short value)
{
return GetBytes(value, 2);
}
/// <summary>
/// Returns the specified 32-bit signed integer value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public byte[] GetBytes(int value)
{
return GetBytes(value, 4);
}
/// <summary>
/// Returns the specified 64-bit signed integer value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public byte[] GetBytes(long value)
{
return GetBytes(value, 8);
}
/// <summary>
/// Returns the specified single-precision floating point value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public byte[] GetBytes(float value)
{
return GetBytes(SingleToInt32Bits(value), 4);
}
/// <summary>
/// Returns the specified 16-bit unsigned integer value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
public byte[] GetBytes(ushort value)
{
return GetBytes(value, 2);
}
/// <summary>
/// Returns the specified 32-bit unsigned integer value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public byte[] GetBytes(uint value)
{
return GetBytes(value, 4);
}
/// <summary>
/// Returns the specified 64-bit unsigned integer value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public byte[] GetBytes(ulong value)
{
return GetBytes(unchecked((long)value), 8);
}
#endregion
#region CopyBytes conversions
/// <summary>
/// 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.
/// </summary>
/// <param name="value">The value to copy bytes for</param>
/// <param name="bytes">The number of significant bytes to copy</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
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);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="value">The value to copy bytes for</param>
/// <param name="bytes">The number of significant bytes to copy</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
protected abstract void CopyBytesImpl(long value, int bytes, byte[] buffer, int index);
/// <summary>
/// Copies the specified Boolean value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">A Boolean value.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public void CopyBytes(bool value, byte[] buffer, int index)
{
CopyBytes(value ? 1 : 0, 1, buffer, index);
}
/// <summary>
/// Copies the specified Unicode character value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">A character to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public void CopyBytes(char value, byte[] buffer, int index)
{
CopyBytes(value, 2, buffer, index);
}
/// <summary>
/// Copies the specified double-precision floating point value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public void CopyBytes(double value, byte[] buffer, int index)
{
CopyBytes(DoubleToInt64Bits(value), 8, buffer, index);
}
/// <summary>
/// Copies the specified 16-bit signed integer value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public void CopyBytes(short value, byte[] buffer, int index)
{
CopyBytes(value, 2, buffer, index);
}
/// <summary>
/// Copies the specified 32-bit signed integer value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public void CopyBytes(int value, byte[] buffer, int index)
{
CopyBytes(value, 4, buffer, index);
}
/// <summary>
/// Copies the specified 64-bit signed integer value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public void CopyBytes(long value, byte[] buffer, int index)
{
CopyBytes(value, 8, buffer, index);
}
/// <summary>
/// Copies the specified single-precision floating point value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public void CopyBytes(float value, byte[] buffer, int index)
{
CopyBytes(SingleToInt32Bits(value), 4, buffer, index);
}
/// <summary>
/// Copies the specified 16-bit unsigned integer value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public void CopyBytes(ushort value, byte[] buffer, int index)
{
CopyBytes(value, 2, buffer, index);
}
/// <summary>
/// Copies the specified 32-bit unsigned integer value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public void CopyBytes(uint value, byte[] buffer, int index)
{
CopyBytes(value, 4, buffer, index);
}
/// <summary>
/// Copies the specified 64-bit unsigned integer value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
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
/// <summary>
/// Union used solely for the equivalent of DoubleToInt64Bits and vice versa.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
struct Int32SingleUnion
{
/// <summary>
/// Int32 version of the value.
/// </summary>
[FieldOffset(0)]
int i;
/// <summary>
/// Single version of the value.
/// </summary>
[FieldOffset(0)]
float f;
/// <summary>
/// Creates an instance representing the given integer.
/// </summary>
/// <param name="i">The integer value of the new instance.</param>
internal Int32SingleUnion(int i)
{
this.f = 0; // Just to keep the compiler happy
this.i = i;
}
/// <summary>
/// Creates an instance representing the given floating point number.
/// </summary>
/// <param name="f">The floating point value of the new instance.</param>
internal Int32SingleUnion(float f)
{
this.i = 0; // Just to keep the compiler happy
this.f = f;
}
/// <summary>
/// Returns the value of the instance as an integer.
/// </summary>
internal int AsInt32
{
get { return i; }
}
/// <summary>
/// Returns the value of the instance as a floating point number.
/// </summary>
internal float AsSingle
{
get { return f; }
}
}
#endregion
}
}

+ 17
- 0
test/cs/Endianness.cs View File

@ -0,0 +1,17 @@
namespace MiscUtil.Conversion
{
/// <summary>
/// Endianness of a converter
/// </summary>
public enum Endianness
{
/// <summary>
/// Little endian - least significant byte first
/// </summary>
LittleEndian,
/// <summary>
/// Big endian - most significant byte first
/// </summary>
BigEndian
}
}

+ 66
- 0
test/cs/LittleEndianBitConverter.cs View File

@ -0,0 +1,66 @@

namespace MiscUtil.Conversion
{
/// <summary>
/// Implementation of EndianBitConverter which converts to/from little-endian
/// byte arrays.
/// </summary>
public sealed class LittleEndianBitConverter : EndianBitConverter
{
/// <summary>
/// Indicates the byte order ("endianess") in which data is converted using this class.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
/// <returns>true if this converter is little-endian, false otherwise.</returns>
public sealed override bool IsLittleEndian()
{
return true;
}
/// <summary>
/// Indicates the byte order ("endianess") in which data is converted using this class.
/// </summary>
public sealed override Endianness Endianness
{
get { return Endianness.LittleEndian; }
}
/// <summary>
/// Copies the specified number of bytes from value to buffer, starting at index.
/// </summary>
/// <param name="value">The value to copy</param>
/// <param name="bytes">The number of bytes to copy</param>
/// <param name="buffer">The buffer to copy the bytes into</param>
/// <param name="index">The index to start at</param>
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;
}
}
/// <summary>
/// Returns a value built from the specified number of bytes from the given buffer,
/// starting at index.
/// </summary>
/// <param name="buffer">The data in byte array format</param>
/// <param name="startIndex">The first index to use</param>
/// <param name="bytesToConvert">The number of bytes to use</param>
/// <returns>The value built from the given bytes</returns>
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;
}
}
}

+ 14
- 0
test/cs/ProtoTest.cs View File

@ -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!");

test/protoMsg.cs → test/cs/protoMsg.cs View File


test/v1/protoMsg.erl → test/erl/erlv1/protoMsg.erl View File


test/v1/protoMsg.hrl → test/erl/erlv1/protoMsg.hrl View File


test/v1/test.erl → test/erl/erlv1/protoTest.erl View File

@ -1,4 +1,4 @@
-module(test).
-module(protoTest).
-include("protoMsg.hrl"). -include("protoMsg.hrl").
-compile(export_all). -compile(export_all).

test/start.bat → test/erl/erlv1/start.bat View File


test/protoMsg.erl → test/erl/protoMsg.erl View File


test/protoMsg.hrl → test/erl/protoMsg.hrl View File


test/test.erl → test/erl/protoTest.erl View File

@ -1,6 +1,6 @@
-module(test).
-module(protoTest).
-include("protoMsg.hrl").
-include("../erl/protoMsg.hrl").
-compile(export_all). -compile(export_all).
encode_int32(N) -> encode_int32(N) ->

test/remake.bat → test/erl/remake.bat View File


test/remake.sh → test/erl/remake.sh View File


+ 1
- 1
test/gen.bat View File

@ -1 +1 @@
genProto ../proto ./ ./
genProto ../proto erl ./erl ./erl lua ./lua cs ./cs

+ 1
- 1
test/gen.sh View File

@ -1 +1 @@
genProto ../proto ./ ./
genProto ../proto erl ./erl ./erl lua ./lua cs ./cs

BIN
test/genProto View File


+ 0
- 2
test/genProto.cmd View File

@ -1,2 +0,0 @@
@echo off
escript.exe "%~dpn0" %*

+ 251
- 0
test/lua/ByteArray.lua View File

@ -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

src/writeLua/ByteArray.lua → test/lua/ByteArray_back.lua View File


test/protoMsg.lua → test/lua/protoMsg.lua View File


test/protoName.lua → test/lua/protoName.lua View File


+ 19
- 0
test/lua/protoTest.lua View File

@ -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

+ 0
- 1
test/v1/start.bat View File

@ -1 +0,0 @@
start werl.exe

Loading…
Cancel
Save