Bencoding encoder and decoder - C# Snipplr Social Repository (original) (raw)
Copy this code and paste it in your HTML
- /*****
- Encoding usage:
- new BDictionary()
- {
- {"Some Key", "Some Value"},
- {"Another Key", 42}
- }.ToBencodedString();
- Decoding usage:
- BencodeDecoder.Decode("d8:Some Key10:Some Value13:Another Valuei42ee");
- Feel free to use it.
- More info about Bencoding at http://wiki.theory.org/BitTorrentSpecification#bencoding
- Originally posted at http://snipplr.com/view/37790/ by SuprDewd.
- */
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace Bencoding
- {
- ///
- /// A class used for decoding Bencoding.
- ///
- public static class BencodeDecoder
- {
- ///
- /// Decodes the string.
- ///
- /// The bencoded string.
- /// An array of root elements.
- public static BElement[] Decode(string bencodedString)
- {
- int index = 0;
- try
- {
- if (bencodedString == null) return null;
- List rootElements = new List();
- while (bencodedString.Length > index)
- {
- rootElements.Add(ReadElement(ref bencodedString, ref index));
- }
- return rootElements.ToArray();
- }
- catch (BencodingException) { throw; }
- catch (Exception e) { throw Error(e); }
- }
- private static BElement ReadElement(ref string bencodedString, ref int index)
- {
- switch (bencodedString[index])
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9': return ReadString(ref bencodedString, ref index);
- case 'i': return ReadInteger(ref bencodedString, ref index);
- case 'l': return ReadList(ref bencodedString, ref index);
- case 'd': return ReadDictionary(ref bencodedString, ref index);
- default: throw Error();
- }
- }
- private static BDictionary ReadDictionary(ref string bencodedString, ref int index)
- {
- index++;
- BDictionary dict = new BDictionary();
- try
- {
- while (bencodedString[index] != 'e')
- {
- BString K = ReadString(ref bencodedString, ref index);
- BElement V = ReadElement(ref bencodedString, ref index);
- dict.Add(K, V);
- }
- }
- catch (BencodingException) { throw; }
- catch (Exception e) { throw Error(e); }
- index++;
- return dict;
- }
- private static BList ReadList(ref string bencodedString, ref int index)
- {
- index++;
- BList lst = new BList();
- try
- {
- while (bencodedString[index] != 'e')
- {
- lst.Add(ReadElement(ref bencodedString, ref index));
- }
- }
- catch (BencodingException) { throw; }
- catch (Exception e) { throw Error(e); }
- index++;
- return lst;
- }
- private static BInteger ReadInteger(ref string bencodedString, ref int index)
- {
- index++;
- int end = bencodedString.IndexOf('e', index);
- if (end == -1) throw Error();
- long integer;
- try
- {
- integer = Convert.ToInt64(bencodedString.Substring(index, end - index));
- index = end + 1;
- }
- catch (Exception e) { throw Error(e); }
- return new BInteger(integer);
- }
- private static BString ReadString(ref string bencodedString, ref int index)
- {
- int length, colon;
- try
- {
- colon = bencodedString.IndexOf(':', index);
- if (colon == -1) throw Error();
- length = Convert.ToInt32(bencodedString.Substring(index, colon - index));
- }
- catch (Exception e) { throw Error(e); }
- index = colon + 1;
- int tmpIndex = index;
- index += length;
- try
- {
- return new BString(bencodedString.Substring(tmpIndex, length));
- }
- catch (Exception e) { throw Error(e); }
- }
- private static Exception Error(Exception e)
- {
- return new BencodingException("Bencoded string invalid.", e);
- }
- private static Exception Error()
- {
- return new BencodingException("Bencoded string invalid.");
- }
- }
- ///
- /// An interface for bencoded elements.
- ///
- public interface BElement
- {
- ///
- /// Generates the bencoded equivalent of the element.
- ///
- /// The bencoded equivalent of the element.
- string ToBencodedString();
- ///
- /// Generates the bencoded equivalent of the element.
- ///
- /// The StringBuilder to append to.
- /// The bencoded equivalent of the element.
- StringBuilder ToBencodedString(StringBuilder u);
- }
- ///
- /// A bencode integer.
- ///
- public class BInteger : BElement, IComparable
- {
- ///
- /// Allows you to set an integer to a BInteger.
- ///
- /// The integer.
- /// The BInteger.
- public static implicit operator BInteger(int i)
- {
- return new BInteger(i);
- }
- ///
- /// The value of the bencoded integer.
- ///
- public long Value { get; set; }
- ///
- /// The main constructor.
- ///
- /// The value of the bencoded integer.
- public BInteger(long value)
- {
- this.Value = value;
- }
- ///
- /// Generates the bencoded equivalent of the integer.
- ///
- /// The bencoded equivalent of the integer.
- public string ToBencodedString()
- {
- return this.ToBencodedString(new StringBuilder()).ToString();
- }
- ///
- /// Generates the bencoded equivalent of the integer.
- ///
- /// The bencoded equivalent of the integer.
- public StringBuilder ToBencodedString(StringBuilder u)
- {
- if (u == null) u = new StringBuilder('i');
- else u.Append('i');
- return u.Append(Value.ToString()).Append('e');
- }
- ///
- public override int GetHashCode()
- {
- return this.Value.GetHashCode();
- }
- ///
- /// Int32.Equals(object)
- ///
- public override bool Equals(object obj)
- {
- try
- {
- return this.Value.Equals(((BInteger)obj).Value);
- }
- catch { return false; }
- }
- ///
- public override string ToString()
- {
- return this.Value.ToString();
- }
- ///
- public int CompareTo(BInteger other)
- {
- return this.Value.CompareTo(other.Value);
- }
- }
- ///
- /// A bencode string.
- ///
- public class BString : BElement, IComparable
- {
- ///
- /// Allows you to set a string to a BString.
- ///
- /// The string.
- /// The BString.
- public static implicit operator BString(string s)
- {
- return new BString(s);
- }
- ///
- /// The value of the bencoded integer.
- ///
- public string Value { get; set; }
- ///
- /// The main constructor.
- ///
- ///
- public BString(string value)
- {
- this.Value = value;
- }
- ///
- /// Generates the bencoded equivalent of the string.
- ///
- /// The bencoded equivalent of the string.
- public string ToBencodedString()
- {
- return this.ToBencodedString(new StringBuilder()).ToString();
- }
- ///
- /// Generates the bencoded equivalent of the string.
- ///
- /// The StringBuilder to append to.
- /// The bencoded equivalent of the string.
- public StringBuilder ToBencodedString(StringBuilder u)
- {
- if (u == null) u = new StringBuilder(this.Value.Length);
- else u.Append(this.Value.Length);
- return u.Append(':').Append(this.Value);
- }
- ///
- public override int GetHashCode()
- {
- return this.Value.GetHashCode();
- }
- ///
- /// String.Equals(object)
- ///
- public override bool Equals(object obj)
- {
- try
- {
- return this.Value.Equals(((BString)obj).Value);
- }
- catch { return false; }
- }
- ///
- public override string ToString()
- {
- return this.Value.ToString();
- }
- ///
- public int CompareTo(BString other)
- {
- return this.Value.CompareTo(other.Value);
- }
- }
- ///
- /// A bencode list.
- ///
- public class BList : List, BElement
- {
- ///
- /// Generates the bencoded equivalent of the list.
- ///
- /// The bencoded equivalent of the list.
- public string ToBencodedString()
- {
- return this.ToBencodedString(new StringBuilder()).ToString();
- }
- ///
- /// Generates the bencoded equivalent of the list.
- ///
- /// The StringBuilder to append to.
- /// The bencoded equivalent of the list.
- public StringBuilder ToBencodedString(StringBuilder u)
- {
- if (u == null) u = new StringBuilder('l');
- else u.Append('l');
- foreach (BElement element in base.ToArray())
- {
- element.ToBencodedString(u);
- }
- return u.Append('e');
- }
- ///
- /// Adds the specified value to the list.
- ///
- /// The specified value.
- public void Add(string value)
- {
- base.Add(new BString(value));
- }
- ///
- /// Adds the specified value to the list.
- ///
- /// The specified value.
- public void Add(int value)
- {
- base.Add(new BInteger(value));
- }
- }
- ///
- /// A bencode dictionary.
- ///
- public class BDictionary : SortedDictionary<BString, BElement>, BElement
- {
- ///
- /// Generates the bencoded equivalent of the dictionary.
- ///
- /// The bencoded equivalent of the dictionary.
- public string ToBencodedString()
- {
- return this.ToBencodedString(new StringBuilder()).ToString();
- }
- ///
- /// Generates the bencoded equivalent of the dictionary.
- ///
- /// The StringBuilder to append to.
- /// The bencoded equivalent of the dictionary.
- public StringBuilder ToBencodedString(StringBuilder u)
- {
- if (u == null) u = new StringBuilder('d');
- else u.Append('d');
- for (int i = 0; i < base.Count; i++)
- {
- base.Keys.ElementAt(i).ToBencodedString(u);
- base.Values.ElementAt(i).ToBencodedString(u);
- }
- return u.Append('e');
- }
- ///
- /// Adds the specified key-value pair to the dictionary.
- ///
- /// The specified key.
- /// The specified value.
- public void Add(string key, BElement value)
- {
- base.Add(new BString(key), value);
- }
- ///
- /// Adds the specified key-value pair to the dictionary.
- ///
- /// The specified key.
- /// The specified value.
- public void Add(string key, string value)
- {
- base.Add(new BString(key), new BString(value));
- }
- ///
- /// Adds the specified key-value pair to the dictionary.
- ///
- /// The specified key.
- /// The specified value.
- public void Add(string key, int value)
- {
- base.Add(new BString(key), new BInteger(value));
- }
- ///
- /// Gets or sets the value assosiated with the specified key.
- ///
- /// The key of the value to get or set.
- /// The value assosiated with the specified key.
- public BElement this[string key]
- {
- get
- {
- return this[new BString(key)];
- }
- set
- {
- this[new BString(key)] = value;
- }
- }
- }
- ///
- /// A bencoding exception.
- ///
- public class BencodingException : FormatException
- {
- ///
- /// Creates a new BencodingException.
- ///
- public BencodingException() { }
- ///
- /// Creates a new BencodingException.
- ///
- /// The message.
- public BencodingException(string message) : base(message) { }
- ///
- /// Creates a new BencodingException.
- ///
- /// The message.
- /// The inner exception.
- public BencodingException(string message, Exception inner) : base(message, inner) { }
- }
- ///
- /// A class with extension methods for use with Bencoding.
- ///
- public static class BencodingExtensions
- {
- ///
- /// Decode the current instance.
- ///
- /// The current instance.
- /// The root elements of the decoded string.
- public static BElement[] BDecode(this string s)
- {
- return BencodeDecoder.Decode(s);
- }
- }
- }