Bencoding encoder and decoder - C# Snipplr Social Repository (original) (raw)

Copy this code and paste it in your HTML

  1. /*****
    • 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.
    • */
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. namespace Bencoding
  7. {
  8. ///
  9. /// A class used for decoding Bencoding.
  10. ///
  11. public static class BencodeDecoder
  12. {
  13. ///
  14. /// Decodes the string.
  15. ///
  16. /// The bencoded string.
  17. /// An array of root elements.
  18. public static BElement[] Decode(string bencodedString)
  19. {
  20. int index = 0;
  21. try
  22. {
  23. if (bencodedString == null) return null;
  24. List rootElements = new List();
  25. while (bencodedString.Length > index)
  26. {
  27. rootElements.Add(ReadElement(ref bencodedString, ref index));
  28. }
  29. return rootElements.ToArray();
  30. }
  31. catch (BencodingException) { throw; }
  32. catch (Exception e) { throw Error(e); }
  33. }
  34. private static BElement ReadElement(ref string bencodedString, ref int index)
  35. {
  36. switch (bencodedString[index])
  37. {
  38. case '0':
  39. case '1':
  40. case '2':
  41. case '3':
  42. case '4':
  43. case '5':
  44. case '6':
  45. case '7':
  46. case '8':
  47. case '9': return ReadString(ref bencodedString, ref index);
  48. case 'i': return ReadInteger(ref bencodedString, ref index);
  49. case 'l': return ReadList(ref bencodedString, ref index);
  50. case 'd': return ReadDictionary(ref bencodedString, ref index);
  51. default: throw Error();
  52. }
  53. }
  54. private static BDictionary ReadDictionary(ref string bencodedString, ref int index)
  55. {
  56. index++;
  57. BDictionary dict = new BDictionary();
  58. try
  59. {
  60. while (bencodedString[index] != 'e')
  61. {
  62. BString K = ReadString(ref bencodedString, ref index);
  63. BElement V = ReadElement(ref bencodedString, ref index);
  64. dict.Add(K, V);
  65. }
  66. }
  67. catch (BencodingException) { throw; }
  68. catch (Exception e) { throw Error(e); }
  69. index++;
  70. return dict;
  71. }
  72. private static BList ReadList(ref string bencodedString, ref int index)
  73. {
  74. index++;
  75. BList lst = new BList();
  76. try
  77. {
  78. while (bencodedString[index] != 'e')
  79. {
  80. lst.Add(ReadElement(ref bencodedString, ref index));
  81. }
  82. }
  83. catch (BencodingException) { throw; }
  84. catch (Exception e) { throw Error(e); }
  85. index++;
  86. return lst;
  87. }
  88. private static BInteger ReadInteger(ref string bencodedString, ref int index)
  89. {
  90. index++;
  91. int end = bencodedString.IndexOf('e', index);
  92. if (end == -1) throw Error();
  93. long integer;
  94. try
  95. {
  96. integer = Convert.ToInt64(bencodedString.Substring(index, end - index));
  97. index = end + 1;
  98. }
  99. catch (Exception e) { throw Error(e); }
  100. return new BInteger(integer);
  101. }
  102. private static BString ReadString(ref string bencodedString, ref int index)
  103. {
  104. int length, colon;
  105. try
  106. {
  107. colon = bencodedString.IndexOf(':', index);
  108. if (colon == -1) throw Error();
  109. length = Convert.ToInt32(bencodedString.Substring(index, colon - index));
  110. }
  111. catch (Exception e) { throw Error(e); }
  112. index = colon + 1;
  113. int tmpIndex = index;
  114. index += length;
  115. try
  116. {
  117. return new BString(bencodedString.Substring(tmpIndex, length));
  118. }
  119. catch (Exception e) { throw Error(e); }
  120. }
  121. private static Exception Error(Exception e)
  122. {
  123. return new BencodingException("Bencoded string invalid.", e);
  124. }
  125. private static Exception Error()
  126. {
  127. return new BencodingException("Bencoded string invalid.");
  128. }
  129. }
  130. ///
  131. /// An interface for bencoded elements.
  132. ///
  133. public interface BElement
  134. {
  135. ///
  136. /// Generates the bencoded equivalent of the element.
  137. ///
  138. /// The bencoded equivalent of the element.
  139. string ToBencodedString();
  140. ///
  141. /// Generates the bencoded equivalent of the element.
  142. ///
  143. /// The StringBuilder to append to.
  144. /// The bencoded equivalent of the element.
  145. StringBuilder ToBencodedString(StringBuilder u);
  146. }
  147. ///
  148. /// A bencode integer.
  149. ///
  150. public class BInteger : BElement, IComparable
  151. {
  152. ///
  153. /// Allows you to set an integer to a BInteger.
  154. ///
  155. /// The integer.
  156. /// The BInteger.
  157. public static implicit operator BInteger(int i)
  158. {
  159. return new BInteger(i);
  160. }
  161. ///
  162. /// The value of the bencoded integer.
  163. ///
  164. public long Value { get; set; }
  165. ///
  166. /// The main constructor.
  167. ///
  168. /// The value of the bencoded integer.
  169. public BInteger(long value)
  170. {
  171. this.Value = value;
  172. }
  173. ///
  174. /// Generates the bencoded equivalent of the integer.
  175. ///
  176. /// The bencoded equivalent of the integer.
  177. public string ToBencodedString()
  178. {
  179. return this.ToBencodedString(new StringBuilder()).ToString();
  180. }
  181. ///
  182. /// Generates the bencoded equivalent of the integer.
  183. ///
  184. /// The bencoded equivalent of the integer.
  185. public StringBuilder ToBencodedString(StringBuilder u)
  186. {
  187. if (u == null) u = new StringBuilder('i');
  188. else u.Append('i');
  189. return u.Append(Value.ToString()).Append('e');
  190. }
  191. ///
  192. public override int GetHashCode()
  193. {
  194. return this.Value.GetHashCode();
  195. }
  196. ///
  197. /// Int32.Equals(object)
  198. ///
  199. public override bool Equals(object obj)
  200. {
  201. try
  202. {
  203. return this.Value.Equals(((BInteger)obj).Value);
  204. }
  205. catch { return false; }
  206. }
  207. ///
  208. public override string ToString()
  209. {
  210. return this.Value.ToString();
  211. }
  212. ///
  213. public int CompareTo(BInteger other)
  214. {
  215. return this.Value.CompareTo(other.Value);
  216. }
  217. }
  218. ///
  219. /// A bencode string.
  220. ///
  221. public class BString : BElement, IComparable
  222. {
  223. ///
  224. /// Allows you to set a string to a BString.
  225. ///
  226. /// The string.
  227. /// The BString.
  228. public static implicit operator BString(string s)
  229. {
  230. return new BString(s);
  231. }
  232. ///
  233. /// The value of the bencoded integer.
  234. ///
  235. public string Value { get; set; }
  236. ///
  237. /// The main constructor.
  238. ///
  239. ///
  240. public BString(string value)
  241. {
  242. this.Value = value;
  243. }
  244. ///
  245. /// Generates the bencoded equivalent of the string.
  246. ///
  247. /// The bencoded equivalent of the string.
  248. public string ToBencodedString()
  249. {
  250. return this.ToBencodedString(new StringBuilder()).ToString();
  251. }
  252. ///
  253. /// Generates the bencoded equivalent of the string.
  254. ///
  255. /// The StringBuilder to append to.
  256. /// The bencoded equivalent of the string.
  257. public StringBuilder ToBencodedString(StringBuilder u)
  258. {
  259. if (u == null) u = new StringBuilder(this.Value.Length);
  260. else u.Append(this.Value.Length);
  261. return u.Append(':').Append(this.Value);
  262. }
  263. ///
  264. public override int GetHashCode()
  265. {
  266. return this.Value.GetHashCode();
  267. }
  268. ///
  269. /// String.Equals(object)
  270. ///
  271. public override bool Equals(object obj)
  272. {
  273. try
  274. {
  275. return this.Value.Equals(((BString)obj).Value);
  276. }
  277. catch { return false; }
  278. }
  279. ///
  280. public override string ToString()
  281. {
  282. return this.Value.ToString();
  283. }
  284. ///
  285. public int CompareTo(BString other)
  286. {
  287. return this.Value.CompareTo(other.Value);
  288. }
  289. }
  290. ///
  291. /// A bencode list.
  292. ///
  293. public class BList : List, BElement
  294. {
  295. ///
  296. /// Generates the bencoded equivalent of the list.
  297. ///
  298. /// The bencoded equivalent of the list.
  299. public string ToBencodedString()
  300. {
  301. return this.ToBencodedString(new StringBuilder()).ToString();
  302. }
  303. ///
  304. /// Generates the bencoded equivalent of the list.
  305. ///
  306. /// The StringBuilder to append to.
  307. /// The bencoded equivalent of the list.
  308. public StringBuilder ToBencodedString(StringBuilder u)
  309. {
  310. if (u == null) u = new StringBuilder('l');
  311. else u.Append('l');
  312. foreach (BElement element in base.ToArray())
  313. {
  314. element.ToBencodedString(u);
  315. }
  316. return u.Append('e');
  317. }
  318. ///
  319. /// Adds the specified value to the list.
  320. ///
  321. /// The specified value.
  322. public void Add(string value)
  323. {
  324. base.Add(new BString(value));
  325. }
  326. ///
  327. /// Adds the specified value to the list.
  328. ///
  329. /// The specified value.
  330. public void Add(int value)
  331. {
  332. base.Add(new BInteger(value));
  333. }
  334. }
  335. ///
  336. /// A bencode dictionary.
  337. ///
  338. public class BDictionary : SortedDictionary<BString, BElement>, BElement
  339. {
  340. ///
  341. /// Generates the bencoded equivalent of the dictionary.
  342. ///
  343. /// The bencoded equivalent of the dictionary.
  344. public string ToBencodedString()
  345. {
  346. return this.ToBencodedString(new StringBuilder()).ToString();
  347. }
  348. ///
  349. /// Generates the bencoded equivalent of the dictionary.
  350. ///
  351. /// The StringBuilder to append to.
  352. /// The bencoded equivalent of the dictionary.
  353. public StringBuilder ToBencodedString(StringBuilder u)
  354. {
  355. if (u == null) u = new StringBuilder('d');
  356. else u.Append('d');
  357. for (int i = 0; i < base.Count; i++)
  358. {
  359. base.Keys.ElementAt(i).ToBencodedString(u);
  360. base.Values.ElementAt(i).ToBencodedString(u);
  361. }
  362. return u.Append('e');
  363. }
  364. ///
  365. /// Adds the specified key-value pair to the dictionary.
  366. ///
  367. /// The specified key.
  368. /// The specified value.
  369. public void Add(string key, BElement value)
  370. {
  371. base.Add(new BString(key), value);
  372. }
  373. ///
  374. /// Adds the specified key-value pair to the dictionary.
  375. ///
  376. /// The specified key.
  377. /// The specified value.
  378. public void Add(string key, string value)
  379. {
  380. base.Add(new BString(key), new BString(value));
  381. }
  382. ///
  383. /// Adds the specified key-value pair to the dictionary.
  384. ///
  385. /// The specified key.
  386. /// The specified value.
  387. public void Add(string key, int value)
  388. {
  389. base.Add(new BString(key), new BInteger(value));
  390. }
  391. ///
  392. /// Gets or sets the value assosiated with the specified key.
  393. ///
  394. /// The key of the value to get or set.
  395. /// The value assosiated with the specified key.
  396. public BElement this[string key]
  397. {
  398. get
  399. {
  400. return this[new BString(key)];
  401. }
  402. set
  403. {
  404. this[new BString(key)] = value;
  405. }
  406. }
  407. }
  408. ///
  409. /// A bencoding exception.
  410. ///
  411. public class BencodingException : FormatException
  412. {
  413. ///
  414. /// Creates a new BencodingException.
  415. ///
  416. public BencodingException() { }
  417. ///
  418. /// Creates a new BencodingException.
  419. ///
  420. /// The message.
  421. public BencodingException(string message) : base(message) { }
  422. ///
  423. /// Creates a new BencodingException.
  424. ///
  425. /// The message.
  426. /// The inner exception.
  427. public BencodingException(string message, Exception inner) : base(message, inner) { }
  428. }
  429. ///
  430. /// A class with extension methods for use with Bencoding.
  431. ///
  432. public static class BencodingExtensions
  433. {
  434. ///
  435. /// Decode the current instance.
  436. ///
  437. /// The current instance.
  438. /// The root elements of the decoded string.
  439. public static BElement[] BDecode(this string s)
  440. {
  441. return BencodeDecoder.Decode(s);
  442. }
  443. }
  444. }