public void ReadPreviousChar()
 {
     var str = "Hello World!";
     using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(str)))
     using (var bs = new BencodeStream(ms))
     {
         Assert.AreEqual(default(char), bs.ReadPreviousChar());
         bs.Read(1);
         Assert.AreEqual('H', bs.ReadPreviousChar());
     }
 }
Esempio n. 2
0
        public static BList DecodeList(BencodeStream stream, Encoding encoding)
        {
            if (stream == null) throw new ArgumentNullException("stream");
            if (encoding == null) throw new ArgumentNullException("encoding");

            if (stream.Length < 2)
                throw new BencodeDecodingException<BList>("Minimum valid length is 2 (an empty list: 'le')", stream.Position);

            // Lists must start with 'l'
            if (stream.ReadChar() != 'l')
                throw new BencodeDecodingException<BList>(string.Format("Must begin with 'l' but began with '{0}'.", stream.ReadPreviousChar()), stream.Position);

            var list = new BList();
            // Loop until next character is the end character 'e' or end of stream
            while (stream.Peek() != 'e' && stream.Peek() != -1)
            {
                // Decode next object in stream
                var bObject = Decode(stream, encoding);
                if (bObject == null)
                    throw new BencodeDecodingException<BList>(string.Format("Invalid object beginning with '{0}'", stream.PeekChar()), stream.Position);

                list.Add(bObject);
            }

            if (stream.ReadChar() != 'e')
                throw new BencodeDecodingException<BList>("Missing end character 'e'.", stream.Position);

            return list;
        }
Esempio n. 3
0
        public static BNumber DecodeNumber(BencodeStream stream)
        {
            if (stream == null) throw new ArgumentNullException("stream");

            if (stream.Length < 3)
                throw new BencodeDecodingException<BNumber>("Minimum valid length of stream is 3 ('i0e').", stream.Position);

            // Numbers must start with 'i'
            if (stream.ReadChar() != 'i')
                throw new BencodeDecodingException<BNumber>(string.Format("Must begin with 'i' but began with '{0}'.", stream.ReadPreviousChar()), stream.Position);

            var isNegative = false;
            var digits = new List<char>();
            while (stream.Peek() != 'e' && stream.Peek() != -1)
            {
                // We do not support numbers that cannot be stored as a long (Int64)
                if (digits.Count >= BNumber.MaxDigits)
                {
                    throw new UnsupportedBencodeException(
                        string.Format(
                            "The number '{0}' has more than 19 digits and cannot be stored as a long (Int64) and therefore is not supported.",
                            digits.AsString()),
                        stream.Position);
                }

                var c = stream.ReadChar();

                // There may be only one '-'
                if (c == '-' && !isNegative)
                {
                    // '-' must be the first char after the beginning 'i'
                    if (digits.Count > 0)
                        throw new BencodeDecodingException<BNumber>("A '-' must be directly after 'i' and before any digits.", stream.Position);

                    isNegative = true;
                    continue;
                }

                // If it is not a digit at this point it is invalid
                if (!c.IsDigit())
                    throw new BencodeDecodingException<BNumber>(string.Format("Must only contain digits and a single prefixed '-'. Invalid character '{0}'", c), stream.Position);

                digits.Add(c);
            }

            // We need at least one digit
            if (digits.Count < 1)
                throw new BencodeDecodingException<BNumber>("It contains no digits.", stream.Position);

            // Leading zeros are not valid
            if (digits[0] == '0' && digits.Count > 1)
                throw new BencodeDecodingException<BNumber>("Leading '0's are not valid.", stream.Position);

            // '-0' is not valid either
            if (digits[0] == '0' && digits.Count == 1 && isNegative)
                throw new BencodeDecodingException<BNumber>("'-0' is not a valid number.", stream.Position);

            if (stream.ReadChar() != 'e')
                throw new BencodeDecodingException<BNumber>("Missing end character 'e'.", stream.Position);

            if (isNegative)
                digits.Insert(0, '-');

            long number;
            if (!long.TryParse(digits.AsString(), out number))
            {
                // This should only happen if the number is bigger than 9,223,372,036,854,775,807 (or smaller than the negative version)
                throw new UnsupportedBencodeException(
                    string.Format(
                        "The value {0} cannot be stored as a long (Int64) and is therefore not supported. The supported values range from {1:N0} to {2:N0}",
                        digits.AsString(), long.MinValue, long.MaxValue),
                    stream.Position);
            }

            return new BNumber(number);
        }
Esempio n. 4
0
        public static BDictionary DecodeDictionary(BencodeStream stream, Encoding encoding)
        {
            if (stream == null) throw new ArgumentNullException("stream");
            if (encoding == null) throw new ArgumentNullException("encoding");

            var startPosition = stream.Position;

            if (stream.Length < 2)
                throw new BencodeDecodingException<BDictionary>("Minimum valid length is 2 (an empty dictionary: 'de')", startPosition);

            // Dictionaries must start with 'd'
            if (stream.ReadChar() != 'd')
                throw new BencodeDecodingException<BDictionary>(string.Format("Must begin with 'd' but began with '{0}'", stream.ReadPreviousChar()), startPosition);

            var dictionary = new BDictionary();
            // Loop until next character is the end character 'e' or end of stream
            while (stream.Peek() != 'e' && stream.Peek() != -1)
            {
                // Decode next string in stream as the key
                BString key;
                try
                {
                    key = DecodeString(stream, encoding);
                }
                catch (BencodeDecodingException<BString> ex)
                {
                    throw new BencodeDecodingException<BDictionary>("Dictionary keys must be strings.", stream.Position);
                }

                // Decode next object in stream as the value
                var value = Decode(stream, encoding);
                if (value == null)
                    throw new BencodeDecodingException<BDictionary>("All keys must have a corresponding value.", stream.Position);

                dictionary.Add(key, value);
            }

            if (stream.ReadChar() != 'e')
                throw new BencodeDecodingException<BDictionary>("Missing end character 'e'.", stream.Position);

            return dictionary;
        }