using System; using System.Globalization; using System.IO; using System.Text; namespace Renci.SshNet.Common { /// /// Specialized for reading and writing data SSH data. /// public class SshDataStream : MemoryStream { /// /// Initializes a new instance of the class with an expandable capacity initialized /// as specified. /// /// The initial size of the internal array in bytes. public SshDataStream(int capacity) : base(capacity) { } /// /// Initializes a new non-resizable instance of the class based on the specified byte array. /// /// The array of unsigned bytes from which to create the current stream. /// is null. public SshDataStream(byte[] buffer) : base(buffer) { } /// /// Gets a value indicating whether all data from the SSH data stream has been read. /// /// /// true if this instance is end of data; otherwise, false. /// public bool IsEndOfData { get { return Position >= Length; } } /// /// Writes an to the SSH data stream. /// /// data to write. public void Write(uint value) { var bytes = value.GetBytes(); Write(bytes, 0, bytes.Length); } /// /// Writes an to the SSH data stream. /// /// data to write. public void Write(ulong value) { var bytes = value.GetBytes(); Write(bytes, 0, bytes.Length); } /// /// Writes a into the SSH data stream. /// /// The to write. public void Write(BigInteger data) { var bytes = data.ToByteArray().Reverse(); WriteBinary(bytes, 0, bytes.Length); } /// /// Writes bytes array data into the SSH data stream. /// /// Byte array data to write. /// is null. public void Write(byte[] data) { if (data == null) throw new ArgumentNullException("data"); Write(data, 0, data.Length); } /// /// Reads a byte array from the SSH data stream. /// /// /// The byte array read from the SSH data stream. /// public byte[] ReadBinary() { var length = ReadUInt32(); if (length > int.MaxValue) { throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Data longer than {0} is not supported.", int.MaxValue)); } return ReadBytes((int)length); } /// /// Writes a buffer preceded by its length into the SSH data stream. /// /// The data to write. /// is null. public void WriteBinary(byte[] buffer) { if (buffer == null) throw new ArgumentNullException("buffer"); WriteBinary(buffer, 0, buffer.Length); } /// /// Writes a buffer preceded by its length into the SSH data stream. /// /// An array of bytes. This method write bytes from buffer to the current SSH data stream. /// The zero-based byte offset in at which to begin writing bytes to the SSH data stream. /// The number of bytes to be written to the current SSH data stream. /// is null. /// The sum of and is greater than the buffer length. /// or is negative. public void WriteBinary(byte[] buffer, int offset, int count) { Write((uint) count); Write(buffer, offset, count); } /// /// Writes string data to the SSH data stream using the specified encoding. /// /// The string data to write. /// The character encoding to use. /// is null. /// is null. public void Write(string s, Encoding encoding) { if (encoding == null) throw new ArgumentNullException("encoding"); var bytes = encoding.GetBytes(s); WriteBinary(bytes, 0, bytes.Length); } /// /// Reads a from the SSH datastream. /// /// /// The read from the SSH data stream. /// public BigInteger ReadBigInt() { var length = ReadUInt32(); var data = ReadBytes((int) length); return new BigInteger(data.Reverse()); } /// /// Reads the next data type from the SSH data stream. /// /// /// The read from the SSH data stream. /// public uint ReadUInt32() { var data = ReadBytes(4); return (uint) (data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]); } /// /// Reads the next data type from the SSH data stream. /// /// /// The read from the SSH data stream. /// public ulong ReadUInt64() { var data = ReadBytes(8); return ((ulong) data[0] << 56 | (ulong) data[1] << 48 | (ulong) data[2] << 40 | (ulong) data[3] << 32 | (ulong) data[4] << 24 | (ulong) data[5] << 16 | (ulong) data[6] << 8 | data[7]); } /// /// Reads the next data type from the SSH data stream. /// /// /// The read from the SSH data stream. /// public string ReadString(Encoding encoding) { var length = ReadUInt32(); if (length > int.MaxValue) { throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Strings longer than {0} is not supported.", int.MaxValue)); } var bytes = ReadBytes((int) length); return encoding.GetString(bytes, 0, bytes.Length); } /// /// Reads next specified number of bytes data type from internal buffer. /// /// Number of bytes to read. /// /// An array of bytes that was read from the internal buffer. /// /// is greater than the internal buffer size. private byte[] ReadBytes(int length) { var data = new byte[length]; var bytesRead = Read(data, 0, length); if (bytesRead < length) throw new ArgumentOutOfRangeException("length"); return data; } /// /// Writes the stream contents to a byte array, regardless of the . /// /// /// This method returns the contents of the as a byte array. /// /// /// If the current instance was constructed on a provided byte array, a copy of the section of the array /// to which this instance has access is returned. /// public override byte[] ToArray() { if (Capacity == Length) { #if FEATURE_MEMORYSTREAM_GETBUFFER return GetBuffer(); #elif FEATURE_MEMORYSTREAM_TRYGETBUFFER ArraySegment buffer; if (TryGetBuffer(out buffer)) return buffer.Array; #endif } return base.ToArray(); } } }