/// <summary> /// Decodes a BEncodedString from the supplied StreamReader /// </summary> /// <param name="reader">The StreamReader containing the BEncodedString</param> internal override void DecodeInternal(RawReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } int letterCount; string length = string.Empty; while ((reader.PeekByte() != -1) && (reader.PeekByte() != ':')) // read in how many characters { length += (char)reader.ReadByte(); // the string is } if (reader.ReadByte() != ':') // remove the ':' { throw new BEncodingException("Invalid data found. Aborting"); } if (!int.TryParse(length, out letterCount)) { throw new BEncodingException(string.Format("Invalid BEncodedString. Length was '{0}' instead of a number", length)); } this.textBytes = new byte[letterCount]; if (reader.Read(textBytes, 0, letterCount) != letterCount) { throw new BEncodingException("Couldn't decode string"); } }
/// <summary> /// Special decoding method for torrent files - allows dictionary attributes to be out of order for the /// overall torrent file, but imposes strict rules on the info dictionary. /// </summary> /// <returns></returns> public static BEncodedDictionary DecodeTorrent(RawReader reader) { BEncodedString key = null; BEncodedValue value = null; var torrent = new BEncodedDictionary(); if (reader.ReadByte() != 'd') { throw new BEncodingException("Invalid data found. Aborting"); // Remove the leading 'd' } while ((reader.PeekByte() != -1) && (reader.PeekByte() != 'e')) { key = (BEncodedString)Decode(reader); // keys have to be BEncoded strings if (reader.PeekByte() == 'd') { value = new BEncodedDictionary(); ((BEncodedDictionary)value).DecodeInternal(reader, key.Text.ToLower().Equals("info")); } else { value = Decode(reader); // the value is a BEncoded value } torrent.dictionary.Add(key, value); } if (reader.ReadByte() != 'e') // remove the trailing 'e' { throw new BEncodingException("Invalid data found. Aborting"); } return(torrent); }
private void DecodeInternal(RawReader reader, bool strictDecoding) { BEncodedString key = null; BEncodedValue value = null; BEncodedString oldkey = null; if (reader.ReadByte() != 'd') { throw new BEncodingException("Invalid data found. Aborting"); // Remove the leading 'd' } while ((reader.PeekByte() != -1) && (reader.PeekByte() != 'e')) { key = (BEncodedString)BEncodedValue.Decode(reader); // keys have to be BEncoded strings if (oldkey != null && oldkey.CompareTo(key) > 0) { if (strictDecoding) { throw new BEncodingException(String.Format( "Illegal BEncodedDictionary. The attributes are not ordered correctly. Old key: {0}, New key: {1}", oldkey, key)); } } oldkey = key; value = BEncodedValue.Decode(reader); // the value is a BEncoded value dictionary.Add(key, value); } if (reader.ReadByte() != 'e') // remove the trailing 'e' { throw new BEncodingException("Invalid data found. Aborting"); } }
static BEncodedNumber DecodeNumber(RawReader reader) { int sign = 1; long result = 0; int val = reader.ReadByte(); if (val == '-') { sign = -1; val = reader.ReadByte(); } do { if (val < '0' || val > '9') { throw new BEncodingException("Invalid number found."); } result = result * 10 + (val - '0'); } while ((val = reader.ReadByte()) != 'e' && val != -1); if (val == -1) //remove the trailing 'e' { throw new BEncodingException("Invalid data found. Aborting."); } result *= sign; return(result); }
internal static BEncodedDictionary DecodeTorrent(RawReader reader) { var torrent = new BEncodedDictionary(); if (reader.ReadByte() != 'd') { throw new BEncodingException("Invalid data found. Aborting"); // Remove the leading 'd' } int read; while ((read = reader.ReadByte()) != -1 && read != 'e') { BEncodedValue value; var key = (BEncodedString)Decode(reader, read); // keys have to be BEncoded strings if ((read = reader.ReadByte()) == 'd') { value = DecodeDictionary(reader, InfoKey.Equals(key)); } else { value = Decode(reader, read); // the value is a BEncoded value } torrent.Add(key, value); } if (read != 'e') // remove the trailing 'e' { throw new BEncodingException("Invalid data found. Aborting"); } return(torrent); }
/// <summary> /// Decodes a BEncodedList from the given StreamReader /// </summary> /// <param name="reader"></param> internal override void DecodeInternal(RawReader reader) { try { if (reader.ReadByte() != 'l') // Remove the leading 'l' { throw new BEncodingException("Invalid data found. Aborting"); } while ((reader.PeekChar() != -1) && ((char)reader.PeekChar() != 'e')) { list.Add(BEncodedValue.Decode(reader)); } if (reader.ReadByte() != 'e') // Remove the trailing 'e' { throw new BEncodingException("Invalid data found. Aborting"); } } catch (BEncodingException ex) { throw new BEncodingException("Couldn't decode list", ex); } catch { throw new BEncodingException("Couldn't decode list"); } }
internal static (BEncodedDictionary torrent, InfoHash infohash) DecodeTorrent(RawReader reader) { var torrent = new BEncodedDictionary(); if (reader.ReadByte() != 'd') { throw new BEncodingException("Invalid data found. Aborting"); // Remove the leading 'd' } int read; InfoHash infoHash = null; // We can save a few resizes and array copies if we pre-allocate // a buffer and then get the memory stream to write to it. We // can trivially pass the final set of bytes to the hash function then. byte[] capturedDataBytes = null; MemoryStream capturedDataStream = null; while ((read = reader.ReadByte()) != -1 && read != 'e') { BEncodedValue value; var key = (BEncodedString)Decode(reader, read); // keys have to be BEncoded strings if ((read = reader.ReadByte()) == 'd') { if (InfoKey.Equals(key)) { capturedDataBytes = new byte[reader.Length - reader.Position]; capturedDataStream = new MemoryStream(capturedDataBytes, true); capturedDataStream.WriteByte((byte)'d'); reader.BeginCaptureData(capturedDataStream); } value = DecodeDictionary(reader, reader.StrictDecoding); if (InfoKey.Equals(key)) { reader.EndCaptureData(); using var hasher = SHA1.Create(); infoHash = new InfoHash(hasher.ComputeHash(capturedDataBytes, 0, (int)capturedDataStream.Position)); } } else { value = Decode(reader, read); // the value is a BEncoded value } torrent.Add(key, value); } if (read != 'e') // remove the trailing 'e' { throw new BEncodingException("Invalid data found. Aborting"); } return(torrent, infoHash); }
/// <summary> /// Decodes a BEncoded number from the supplied RawReader /// </summary> /// <param name="reader">RawReader containing a BEncoded Number</param> internal override void DecodeInternal(RawReader reader) { var sign = 1; if (reader == null) { throw new ArgumentNullException("reader"); } try { if (reader.ReadByte() != 'i') // remove the leading 'i' { throw new BEncodingException("Invalid data found. Aborting."); } if (reader.PeekChar() == '-') { sign = -1; reader.ReadChar(); } int letter; while (((letter = reader.PeekChar()) != -1) && letter != 'e') { if (letter < '0' || letter > '9') { throw new BEncodingException("Invalid number found."); } number = number * 10 + (letter - '0'); reader.ReadChar(); } if (reader.ReadByte() != 'e') //remove the trailing 'e' { throw new BEncodingException("Invalid data found. Aborting."); } number *= sign; } catch (BEncodingException ex) { throw new BEncodingException("Couldn't decode number", ex); } catch { throw new BEncodingException("Couldn't decode number"); } }
static BEncodedString DecodeString(RawReader reader, int length) { int read; while ((read = reader.ReadByte()) != -1 && read != ':') { if (read < '0' || read > '9') { throw new BEncodingException($"Invalid BEncodedString. Length was '{length}' instead of a number"); } length = length * 10 + (read - '0'); } if (read != ':') { throw new BEncodingException("Invalid data found. Aborting"); } var bytes = new byte[length]; if (reader.Read(bytes, 0, length) != length) { throw new BEncodingException("Couldn't decode string"); } return(new BEncodedString(bytes)); }
static BEncodedDictionary DecodeDictionary(RawReader reader, bool strictDecoding) { int read; BEncodedString oldkey = null; var dictionary = new BEncodedDictionary(); while ((read = reader.ReadByte()) != -1 && read != 'e') { BEncodedString key = DecodeString(reader, read - '0'); // keys have to be BEncoded strings if (oldkey != null && oldkey.CompareTo(key) > 0) { if (strictDecoding) { throw new BEncodingException( $"Illegal BEncodedDictionary. The attributes are not ordered correctly. Old key: {oldkey}, New key: {key}"); } } oldkey = key; BEncodedValue value = Decode(reader); // the value is a BEncoded value dictionary.Add(key, value); } if (read != 'e') // remove the trailing 'e' { throw new BEncodingException("Invalid data found. Aborting"); } return(dictionary); }
/// <summary> /// Special decoding method for torrent files - allows dictionary attributes to be out of order for the /// overall torrent file, but imposes strict rules on the info dictionary. /// </summary> /// <returns></returns> public static BEncodedDictionary DecodeTorrent(RawReader reader) { BEncodedString key = null; BEncodedValue value = null; BEncodedDictionary torrent = new BEncodedDictionary(); try { if (reader.ReadByte() != 'd') { throw new BEncodingException("Invalid data found. Aborting"); // Remove the leading 'd' } while ((reader.PeekChar() != -1) && ((char)reader.PeekChar() != 'e')) { key = (BEncodedString)BEncodedValue.Decode(reader); // keys have to be BEncoded strings if (reader.PeekChar() == 'd') { value = new BEncodedDictionary(); if (key.Text.ToLower().Equals("info")) { ((BEncodedDictionary)value).DecodeInternal(reader, true); } else { ((BEncodedDictionary)value).DecodeInternal(reader, false); } } else { value = BEncodedValue.Decode(reader); // the value is a BEncoded value } torrent.dictionary.Add(key, value); } if (reader.ReadByte() != 'e') // remove the trailing 'e' { throw new BEncodingException("Invalid data found. Aborting"); } return(torrent); } catch (Exception ex) { throw new BEncodingException("Couldn't decode dictionary", ex); } }
/// <summary> /// Decodes a BEncodedList from the given StreamReader /// </summary> /// <param name="reader"></param> internal override void DecodeInternal(RawReader reader) { if (reader.ReadByte() != 'l') // Remove the leading 'l' { throw new BEncodingException("Invalid data found. Aborting"); } while ((reader.PeekByte() != -1) && (reader.PeekByte() != 'e')) { list.Add(BEncodedValue.Decode(reader)); } if (reader.ReadByte() != 'e') // Remove the trailing 'e' { throw new BEncodingException("Invalid data found. Aborting"); } }
static BEncodedList DecodeList(RawReader reader) { var list = new BEncodedList(); int read; while ((read = reader.ReadByte()) != -1 && read != 'e') { list.Add(Decode(reader, read)); } if (read != 'e') // Remove the trailing 'e' { throw new BEncodingException("Invalid data found. Aborting"); } return(list); }
internal static BEncodedValue Decode(RawReader reader) => Decode(reader, reader.ReadByte());