/// <summary> /// Parses a stream into an <see cref="IBObject"/> of type <typeparamref name="T"/>. /// </summary> /// <typeparam name="T">The type of <see cref="IBObject"/> to parse as.</typeparam> /// <param name="parser"></param> /// <param name="stream">The stream to parse.</param> /// <returns>The parsed object.</returns> public static T Parse <T>(this IBencodeParser parser, Stream stream) where T : class, IBObject { using (var reader = new BencodeReader(stream, leaveOpen: true)) { return(parser.Parse <T>(reader)); } }
/// <summary> /// Parses a stream into an <see cref="IBObject"/>. /// </summary> /// <param name="parser"></param> /// <param name="stream">The stream to parse.</param> /// <returns>The parsed object.</returns> public static IBObject Parse(this IBencodeParser parser, Stream stream) { using (var reader = new BencodeReader(stream, leaveOpen: true)) { return(parser.Parse(reader)); } }
public void ReadMoreBytesThanInStream() { using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("Hello World!"))) using (var bs = new BencodeReader(ms)) { var bytes = new byte[20]; var read = bs.Read(bytes); read.Should().Be(12); Assert.Equal("Hello World!", Encoding.UTF8.GetString(bytes, 0, read)); } }
public void ReadZeroBytes() { using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("Hello World!"))) using (var bs = new BencodeReader(ms)) { var bytes = new byte[0]; var read = bs.Read(bytes); read.Should().Be(0); Assert.Equal("", Encoding.UTF8.GetString(bytes)); } }
public void ReadCharChangesStreamPosition() { var str = "Hello World!"; using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(str))) using (var bs = new BencodeReader(ms)) { bs.Position.Should().Be(0); bs.ReadChar(); bs.Position.Should().Be(1); bs.ReadChar(); bs.Position.Should().Be(2); } }
public void ReadBytesChangesStreamPosition() { var str = "Hello World!"; using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(str))) using (var bs = new BencodeReader(ms)) { Assert.Equal(0, bs.Position); var bytes = new byte[str.Length]; var read = bs.Read(bytes); read.Should().Be(12); bs.Position.Should().Be(12); Assert.Equal(str, Encoding.UTF8.GetString(bytes)); } }
public void ReadBytesWhenNotAllBytesAreReadOnFirstRead(Stream stream) { var ms = new MemoryStream(Encoding.UTF8.GetBytes("abcdef")); var bs = new BencodeReader(stream); stream.Read(null, 0, 0).ReturnsForAnyArgs( x => ms.Read(x.Arg <byte[]>(), x.ArgAt <int>(1), 2), x => ms.Read(x.Arg <byte[]>(), x.ArgAt <int>(1), 2), x => ms.Read(x.Arg <byte[]>(), x.ArgAt <int>(1), 2) ); var bytes = new byte[6]; var read = bs.Read(bytes); read.Should().Be(6); Assert.Equal("abcdef", Encoding.UTF8.GetString(bytes, 0, read)); }
/// <summary> /// Parses the next <see cref="BString"/> from the reader. /// </summary> /// <param name="reader">The reader to parse from.</param> /// <returns>The parsed <see cref="BString"/>.</returns> /// <exception cref="InvalidBencodeException{BString}">Invalid bencode.</exception> /// <exception cref="UnsupportedBencodeException{BString}">The bencode is unsupported by this library.</exception> public override BString Parse(BencodeReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } // Minimum valid bencode string is '0:' meaning an empty string if (reader.Length < MinimumLength) { throw InvalidBencodeException <BString> .BelowMinimumLength(MinimumLength, reader.Length.Value, reader.Position); } var startPosition = reader.Position; var buffer = ArrayPool <char> .Shared.Rent(BString.LengthMaxDigits); try { var lengthString = buffer.AsSpan(); var lengthStringCount = 0; for (var c = reader.ReadChar(); c != default && c.IsDigit(); c = reader.ReadChar()) { EnsureLengthStringBelowMaxLength(lengthStringCount, startPosition); lengthString[lengthStringCount++] = c; } EnsurePreviousCharIsColon(reader.PreviousChar, reader.Position); var stringLength = ParseStringLength(lengthString, lengthStringCount, startPosition); var bytes = new byte[stringLength]; var bytesRead = reader.Read(bytes); EnsureExpectedBytesRead(bytesRead, stringLength, startPosition); return(new BString(bytes, Encoding)); } finally { ArrayPool <char> .Shared.Return(buffer); } }
/// <summary> /// Parses the next <see cref="BNumber"/> from the reader. /// </summary> /// <param name="reader">The reader to parse from.</param> /// <returns>The parsed <see cref="BNumber"/>.</returns> /// <exception cref="InvalidBencodeException{BNumber}">Invalid bencode.</exception> /// <exception cref="UnsupportedBencodeException{BNumber}">The bencode is unsupported by this library.</exception> public override BNumber Parse(BencodeReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (reader.Length < MinimumLength) { throw InvalidBencodeException <BNumber> .BelowMinimumLength(MinimumLength, reader.Length.Value, reader.Position); } var startPosition = reader.Position; // Numbers must start with 'i' if (reader.ReadChar() != 'i') { throw InvalidBencodeException <BNumber> .UnexpectedChar('i', reader.PreviousChar, startPosition); } using var digits = MemoryPool <char> .Shared.Rent(BNumber.MaxDigits); var digitCount = 0; for (var c = reader.ReadChar(); c != default && c != 'e'; c = reader.ReadChar()) { digits.Memory.Span[digitCount++] = c; } if (digitCount == 0) { throw NoDigitsException(startPosition); } // Last read character should be 'e' if (reader.PreviousChar != 'e') { throw InvalidBencodeException <BNumber> .MissingEndChar(startPosition); } return(ParseNumber(digits.Memory.Span.Slice(0, digitCount), startPosition)); }
public void ReadChar() { var str = "Hello World!"; using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(str))) using (var bs = new BencodeReader(ms)) { bs.ReadChar().Should().Be('H'); bs.ReadChar().Should().Be('e'); bs.ReadChar().Should().Be('l'); bs.ReadChar().Should().Be('l'); bs.ReadChar().Should().Be('o'); bs.ReadChar().Should().Be(' '); bs.ReadChar().Should().Be('W'); bs.ReadChar().Should().Be('o'); bs.ReadChar().Should().Be('r'); bs.ReadChar().Should().Be('l'); bs.ReadChar().Should().Be('d'); bs.ReadChar().Should().Be('!'); bs.ReadChar().Should().Be(default);
/// <summary> /// Parses the next <see cref="BList"/> from the reader. /// </summary> /// <param name="reader">The reader to parse from.</param> /// <returns>The parsed <see cref="BList"/>.</returns> /// <exception cref="InvalidBencodeException{BList}">Invalid bencode.</exception> public override BList Parse(BencodeReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (reader.Length < MinimumLength) { throw InvalidBencodeException <BList> .BelowMinimumLength(MinimumLength, reader.Length.Value, reader.Position); } var startPosition = reader.Position; // Lists must start with 'l' if (reader.ReadChar() != 'l') { throw InvalidBencodeException <BList> .UnexpectedChar('l', reader.PreviousChar, startPosition); } var list = new BList(); // Loop until next character is the end character 'e' or end of stream while (reader.PeekChar() != 'e' && reader.PeekChar() != default) { // Decode next object in stream var bObject = BencodeParser.Parse(reader); list.Add(bObject); } if (reader.ReadChar() != 'e') { throw InvalidBencodeException <BList> .MissingEndChar(startPosition); } return(list); }
/// <summary> /// Parses the next <see cref="BDictionary"/> from the reader as a <see cref="Torrent"/>. /// </summary> /// <param name="reader">The reader to parse from.</param> /// <returns>The parsed <see cref="Torrent"/>.</returns> public override Torrent Parse(BencodeReader reader) { var data = BencodeParser.Parse <BDictionary>(reader); return(CreateTorrent(data)); }
internal static void SkipBytes(this BencodeReader reader, int length) { reader.Read(new byte[length]); }
/// <summary> /// Parses an <see cref="IBObject"/> of type <typeparamref name="T"/> from a <see cref="BencodeReader"/>. /// </summary> /// <param name="reader">The reader to read from.</param> /// <returns>The parsed object.</returns> public abstract T Parse(BencodeReader reader);
IBObject IBObjectParser.Parse(BencodeReader reader) { return(Parse(reader)); }
public override IBObject Parse(BencodeReader stream) { return(Substitute.Parse(stream)); }
/// <summary> /// Parses the next <see cref="BDictionary"/> and its contained keys and values from the reader. /// </summary> /// <param name="reader">The reader to parse from.</param> /// <returns>The parsed <see cref="BDictionary"/>.</returns> /// <exception cref="InvalidBencodeException{BDictionary}">Invalid bencode.</exception> public override BDictionary Parse(BencodeReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (reader.Length < MinimumLength) { throw InvalidBencodeException <BDictionary> .BelowMinimumLength(MinimumLength, reader.Length.Value, reader.Position); } var startPosition = reader.Position; // Dictionaries must start with 'd' if (reader.ReadChar() != 'd') { throw InvalidBencodeException <BDictionary> .UnexpectedChar('d', reader.PreviousChar, startPosition); } var dictionary = new BDictionary(); // Loop until next character is the end character 'e' or end of stream while (reader.PeekChar() != 'e' && reader.PeekChar() != default) { BString key; try { // Decode next string in stream as the key key = BencodeParser.Parse <BString>(reader); } catch (BencodeException ex) { throw InvalidException("Could not parse dictionary key. Keys must be strings.", ex, startPosition); } IBObject value; try { // Decode next object in stream as the value value = BencodeParser.Parse(reader); } catch (BencodeException ex) { throw InvalidException($"Could not parse dictionary value for the key '{key}'. There needs to be a value for each key.", ex, startPosition); } if (dictionary.ContainsKey(key)) { throw InvalidException($"The dictionary already contains the key '{key}'. Duplicate keys are not supported.", startPosition); } dictionary.Add(key, value); } if (reader.ReadChar() != 'e') { throw InvalidBencodeException <BDictionary> .MissingEndChar(startPosition); } return(dictionary); }