2014-05-13 17:57:46 +00:00
|
|
|
using System;
|
|
|
|
using System.IO;
|
|
|
|
|
|
|
|
namespace MonoTorrent.BEncoding
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// Base interface for all BEncoded values.
|
|
|
|
/// </summary>
|
|
|
|
public abstract class BEncodedValue
|
|
|
|
{
|
|
|
|
internal abstract void DecodeInternal(RawReader reader);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Encodes the BEncodedValue into a byte array
|
|
|
|
/// </summary>
|
|
|
|
/// <returns>Byte array containing the BEncoded Data</returns>
|
|
|
|
public byte[] Encode()
|
|
|
|
{
|
|
|
|
byte[] buffer = new byte[LengthInBytes()];
|
|
|
|
if (Encode(buffer, 0) != buffer.Length)
|
|
|
|
throw new BEncodingException("Error encoding the data");
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Encodes the BEncodedValue into the supplied buffer
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="buffer">The buffer to encode the information to</param>
|
|
|
|
/// <param name="offset">The offset in the buffer to start writing the data</param>
|
|
|
|
/// <returns></returns>
|
|
|
|
public abstract int Encode(byte[] buffer, int offset);
|
|
|
|
|
2019-12-22 22:08:53 +00:00
|
|
|
public static T Clone<T>(T value)
|
2014-05-13 17:57:46 +00:00
|
|
|
where T : BEncodedValue
|
|
|
|
{
|
2019-12-22 22:08:53 +00:00
|
|
|
Check.Value(value);
|
|
|
|
return (T)BEncodedValue.Decode(value.Encode());
|
2014-05-13 17:57:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Interface for all BEncoded values
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="data">The byte array containing the BEncoded data</param>
|
|
|
|
/// <returns></returns>
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Decode BEncoded data in the given byte array
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="buffer">The byte array containing the BEncoded data</param>
|
|
|
|
/// <param name="offset">The offset at which the data starts at</param>
|
|
|
|
/// <param name="length">The number of bytes to be decoded</param>
|
|
|
|
/// <returns>BEncodedValue containing the data that was in the byte[]</returns>
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-12-22 21:24:11 +00:00
|
|
|
/// Decode BEncoded data in the given stream
|
2014-05-13 17:57:46 +00:00
|
|
|
/// </summary>
|
|
|
|
/// <param name="stream">The stream containing the BEncoded data</param>
|
|
|
|
/// <returns>BEncodedValue containing the data that was in the stream</returns>
|
|
|
|
public static BEncodedValue Decode(Stream stream)
|
|
|
|
{
|
|
|
|
if (stream == null)
|
|
|
|
throw new ArgumentNullException("stream");
|
|
|
|
|
2018-02-06 23:10:33 +00:00
|
|
|
return Decode(new RawReader(stream, false));
|
2014-05-13 17:57:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Decode BEncoded data in the given RawReader
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="reader">The RawReader containing the BEncoded data</param>
|
|
|
|
/// <returns>BEncodedValue containing the data that was in the stream</returns>
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Interface for all BEncoded values
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="data">The byte array containing the BEncoded data</param>
|
|
|
|
/// <returns></returns>
|
|
|
|
public static T Decode<T>(byte[] data) where T : BEncodedValue
|
|
|
|
{
|
|
|
|
return (T)BEncodedValue.Decode(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Decode BEncoded data in the given byte array
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="buffer">The byte array containing the BEncoded data</param>
|
|
|
|
/// <param name="offset">The offset at which the data starts at</param>
|
|
|
|
/// <param name="length">The number of bytes to be decoded</param>
|
|
|
|
/// <returns>BEncodedValue containing the data that was in the byte[]</returns>
|
|
|
|
public static T Decode<T>(byte[] buffer, int offset, int length) where T : BEncodedValue
|
|
|
|
{
|
|
|
|
return BEncodedValue.Decode<T>(buffer, offset, length, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static T Decode<T>(byte[] buffer, int offset, int length, bool strictDecoding) where T : BEncodedValue
|
|
|
|
{
|
|
|
|
return (T)BEncodedValue.Decode(buffer, offset, length, strictDecoding);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-12-22 21:24:11 +00:00
|
|
|
/// Decode BEncoded data in the given stream
|
2014-05-13 17:57:46 +00:00
|
|
|
/// </summary>
|
|
|
|
/// <param name="stream">The stream containing the BEncoded data</param>
|
|
|
|
/// <returns>BEncodedValue containing the data that was in the stream</returns>
|
|
|
|
public static T Decode<T>(Stream stream) where T : BEncodedValue
|
|
|
|
{
|
|
|
|
return (T)BEncodedValue.Decode(stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static T Decode<T>(RawReader reader) where T : BEncodedValue
|
|
|
|
{
|
|
|
|
return (T)BEncodedValue.Decode(reader);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Returns the size of the byte[] needed to encode this BEncodedValue
|
|
|
|
/// </summary>
|
|
|
|
/// <returns></returns>
|
|
|
|
public abstract int LengthInBytes();
|
|
|
|
}
|
|
|
|
}
|