using System; using System.IO; namespace MonoTorrent.BEncoding { /// /// Base interface for all BEncoded values. /// public abstract class BEncodedValue { internal abstract void DecodeInternal(RawReader reader); /// /// Encodes the BEncodedValue into a byte array /// /// Byte array containing the BEncoded Data public byte[] Encode() { byte[] buffer = new byte[LengthInBytes()]; if (Encode(buffer, 0) != buffer.Length) throw new BEncodingException("Error encoding the data"); return buffer; } /// /// Encodes the BEncodedValue into the supplied buffer /// /// The buffer to encode the information to /// The offset in the buffer to start writing the data /// public abstract int Encode(byte[] buffer, int offset); public static T Clone(T value) where T : BEncodedValue { Check.Value(value); return (T)BEncodedValue.Decode(value.Encode()); } /// /// Interface for all BEncoded values /// /// The byte array containing the BEncoded data /// public static BEncodedValue Decode(byte[] data) { if (data == null) throw new ArgumentNullException("data"); using (RawReader stream = new RawReader(new MemoryStream(data))) return (Decode(stream)); } internal static BEncodedValue Decode(byte[] buffer, bool strictDecoding) { return Decode(buffer, 0, buffer.Length, strictDecoding); } /// /// Decode BEncoded data in the given byte array /// /// The byte array containing the BEncoded data /// The offset at which the data starts at /// The number of bytes to be decoded /// BEncodedValue containing the data that was in the byte[] public static BEncodedValue Decode(byte[] buffer, int offset, int length) { return Decode(buffer, offset, length, true); } public static BEncodedValue Decode(byte[] buffer, int offset, int length, bool strictDecoding) { if (buffer == null) throw new ArgumentNullException("buffer"); if (offset < 0 || length < 0) throw new IndexOutOfRangeException("Neither offset or length can be less than zero"); if (offset > buffer.Length - length) throw new ArgumentOutOfRangeException("length"); using (RawReader reader = new RawReader(new MemoryStream(buffer, offset, length), strictDecoding)) return (BEncodedValue.Decode(reader)); } /// /// Decode BEncoded data in the given stream /// /// The stream containing the BEncoded data /// BEncodedValue containing the data that was in the stream public static BEncodedValue Decode(Stream stream) { if (stream == null) throw new ArgumentNullException("stream"); return Decode(new RawReader(stream, false)); } /// /// Decode BEncoded data in the given RawReader /// /// The RawReader containing the BEncoded data /// BEncodedValue containing the data that was in the stream public static BEncodedValue Decode(RawReader reader) { if (reader == null) throw new ArgumentNullException("reader"); BEncodedValue data; switch (reader.PeekByte()) { case ('i'): // Integer data = new BEncodedNumber(); break; case ('d'): // Dictionary data = new BEncodedDictionary(); break; case ('l'): // List data = new BEncodedList(); break; case ('1'): // String case ('2'): case ('3'): case ('4'): case ('5'): case ('6'): case ('7'): case ('8'): case ('9'): case ('0'): data = new BEncodedString(); break; default: throw new BEncodingException("Could not find what value to decode"); } data.DecodeInternal(reader); return data; } /// /// Interface for all BEncoded values /// /// The byte array containing the BEncoded data /// public static T Decode(byte[] data) where T : BEncodedValue { return (T)BEncodedValue.Decode(data); } /// /// Decode BEncoded data in the given byte array /// /// The byte array containing the BEncoded data /// The offset at which the data starts at /// The number of bytes to be decoded /// BEncodedValue containing the data that was in the byte[] public static T Decode(byte[] buffer, int offset, int length) where T : BEncodedValue { return BEncodedValue.Decode(buffer, offset, length, true); } public static T Decode(byte[] buffer, int offset, int length, bool strictDecoding) where T : BEncodedValue { return (T)BEncodedValue.Decode(buffer, offset, length, strictDecoding); } /// /// Decode BEncoded data in the given stream /// /// The stream containing the BEncoded data /// BEncodedValue containing the data that was in the stream public static T Decode(Stream stream) where T : BEncodedValue { return (T)BEncodedValue.Decode(stream); } public static T Decode(RawReader reader) where T : BEncodedValue { return (T)BEncodedValue.Decode(reader); } /// /// Returns the size of the byte[] needed to encode this BEncodedValue /// /// public abstract int LengthInBytes(); } }