using System; using System.Text; namespace S22.Sasl { /// /// A utility class modeled after the BCL StringBuilder to simplify /// building binary-data messages. /// internal class ByteBuilder { /// /// The actual byte buffer. /// byte[] buffer = new byte[1024]; /// /// The current position in the buffer. /// int position = 0; /// /// The length of the underlying data buffer. /// public int Length { get { return position; } } /// /// Resizes the internal byte buffer. /// /// Amount in bytes by which to increase the /// size of the buffer. void Resize(int amount = 1024) { byte[] newBuffer = new byte[buffer.Length + amount]; Array.Copy(buffer, newBuffer, buffer.Length); buffer = newBuffer; } /// /// Appends one or several byte values to this instance. /// /// Byte values to append. /// A reference to the calling instance. public ByteBuilder Append(params byte[] values) { if ((position + values.Length) >= buffer.Length) Resize(); foreach (byte b in values) buffer[position++] = b; return this; } /// /// Appends the specified number of bytes from the specified buffer /// starting at the specified offset to this instance. /// /// The buffer to append bytes from. /// The offset into the buffert at which to start /// reading bytes from. /// The number of bytes to read from the buffer. /// A reference to the calling instance. public ByteBuilder Append(byte[] buffer, int offset, int count) { if ((position + count) >= buffer.Length) Resize(); for (int i = 0; i < count; i++) this.buffer[position++] = buffer[offset + i]; return this; } /// /// Appends the specified 32-bit integer value to this instance. /// /// A 32-bit integer value to append. /// Set this to true, to append the value as /// big-endian. /// A reference to the calling instance. public ByteBuilder Append(int value, bool bigEndian = false) { if ((position + 4) >= buffer.Length) Resize(); int[] o = bigEndian ? new int[4] { 3, 2, 1, 0 } : new int[4] { 0, 1, 2, 3 }; for (int i = 0; i < 4; i++) buffer[position++] = (byte) ((value >> (o[i] * 8)) & 0xFF); return this; } /// /// Appends the specified 16-bit short value to this instance. /// /// A 16-bit short value to append. /// Set this to true, to append the value as /// big-endian. /// A reference to the calling instance. public ByteBuilder Append(short value, bool bigEndian = false) { if ((position + 2) >= buffer.Length) Resize(); int[] o = bigEndian ? new int[2] { 1, 0 } : new int[2] { 0, 1 }; for (int i = 0; i < 2; i++) buffer[position++] = (byte) ((value >> (o[i] * 8)) & 0xFF); return this; } /// /// Appends the specified 16-bit unsigend short value to this instance. /// /// A 16-bit unsigend short value to append. /// Set this to true, to append the value as /// big-endian. /// A reference to the calling instance. public ByteBuilder Append(ushort value, bool bigEndian = false) { if ((position + 2) >= buffer.Length) Resize(); int[] o = bigEndian ? new int[2] { 1, 0 } : new int[2] { 0, 1 }; for (int i = 0; i < 2; i++) buffer[position++] = (byte) ((value >> (o[i] * 8)) & 0xFF); return this; } /// /// Appends the specified 32-bit unsigned integer value to this instance. /// /// A 32-bit unsigned integer value to append. /// Set this to true, to append the value as /// big-endian. /// A reference to the calling instance. public ByteBuilder Append(uint value, bool bigEndian = false) { if ((position + 4) >= buffer.Length) Resize(); int[] o = bigEndian ? new int[4] { 3, 2, 1, 0 } : new int[4] { 0, 1, 2, 3 }; for (int i = 0; i < 4; i++) buffer[position++] = (byte) ((value >> (o[i] * 8)) & 0xFF); return this; } /// /// Appends the specified 64-bit integer value to this instance. /// /// A 64-bit integer value to append. /// Set this to true, to append the value as /// big-endian. /// A reference to the calling instance. public ByteBuilder Append(long value, bool bigEndian = false) { if ((position + 8) >= buffer.Length) Resize(); int[] o = bigEndian ? new int[8] { 7, 6, 5, 4, 3, 2, 1, 0 } : new int[8] { 0, 1, 2, 3, 4, 5, 6, 7 }; for (int i = 0; i < 8; i++) buffer[position++] = (byte) ((value >> (o[i] * 8)) & 0xFF); return this; } /// /// Appends the specified string using the specified encoding to this /// instance. /// /// The string vale to append. /// The encoding to use for decoding the string value /// into a sequence of bytes. If this is null, ASCII encoding is used as a /// default. /// A reference to the calling instance. public ByteBuilder Append(string value, Encoding encoding = null) { if (encoding == null) encoding = Encoding.ASCII; byte[] bytes = encoding.GetBytes(value); if ((position + bytes.Length) >= buffer.Length) Resize(); foreach (byte b in bytes) buffer[position++] = b; return this; } /// /// Returns the ByteBuilder's content as an array of bytes. /// /// An array of bytes. public byte[] ToArray() { // Fixme: Do this properly. byte[] b = new byte[position]; Array.Copy(buffer, b, position); return b; } /// /// Removes all bytes from the current ByteBuilder instance. /// public void Clear() { buffer = new byte[1024]; position = 0; } } }