Skip to main content

mtorrent_utils/
benc.rs

1use derive_more::Display;
2use std::collections::BTreeMap;
3use std::error::Error;
4use std::io::Write;
5use std::num::ParseIntError;
6use std::{fmt, io, str};
7use thiserror::Error;
8
9/// Bencoded element.
10#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Clone)]
11pub enum Element {
12    Integer(i64),
13    ByteString(Vec<u8>),
14    List(Vec<Element>),
15    Dictionary(BTreeMap<Element, Element>),
16}
17
18impl Element {
19    /// Parse bencoded bytes.
20    pub fn from_bytes(src: &[u8]) -> Result<Element, ParseError> {
21        match read_element(src) {
22            Ok((entity, _)) => Ok(entity),
23            Err(e) => Err(e),
24        }
25    }
26
27    /// Parse bencoded bytes. Returns the produced [`Element`] and the number of parsed bytes.
28    pub fn from_bytes_with_len(src: &[u8]) -> Result<(Element, usize), ParseError> {
29        let (entity, rest) = read_element(src)?;
30        Ok((entity, src.len() - rest.len()))
31    }
32
33    /// Serialize to a vec of bytes.
34    pub fn encode(&self) -> Vec<u8> {
35        let mut dest = Vec::<u8>::new();
36        write_element(self, &mut dest);
37        dest
38    }
39}
40
41impl From<&str> for Element {
42    fn from(text: &str) -> Self {
43        Element::ByteString(Vec::<u8>::from(text))
44    }
45}
46
47impl From<String> for Element {
48    fn from(value: String) -> Self {
49        Element::ByteString(value.into_bytes())
50    }
51}
52
53impl From<i64> for Element {
54    fn from(number: i64) -> Self {
55        Element::Integer(number)
56    }
57}
58
59impl fmt::Display for Element {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        const INDENT_INCREMENT: usize = 3;
62        fn write_entity(
63            entity: &Element,
64            f: &mut fmt::Formatter<'_>,
65            last_indent: usize,
66            ignore_first_indent: bool,
67        ) -> fmt::Result {
68            let first_indent = if ignore_first_indent { 0 } else { last_indent };
69            match entity {
70                Element::ByteString(data) => match std::str::from_utf8(data) {
71                    Ok(text) => write!(f, "{:first_indent$}\"{}\"", ' ', text)?,
72                    Err(_) => write!(f, "{:first_indent$}<{} raw bytes>", ' ', data.len())?,
73                },
74                Element::Integer(number) => write!(f, "{:first_indent$}{}", ' ', number)?,
75                Element::List(elements) => {
76                    writeln!(f, "{:first_indent$}[", ' ')?;
77                    for e in elements {
78                        write_entity(e, f, last_indent + INDENT_INCREMENT, false)?;
79                        writeln!(f, ",")?;
80                    }
81                    write!(f, "{:last_indent$}]", ' ')?;
82                }
83                Element::Dictionary(map) => {
84                    writeln!(f, "{:first_indent$}{{", ' ')?;
85                    for (key, val) in map {
86                        write_entity(key, f, last_indent + INDENT_INCREMENT, false)?;
87                        write!(f, ":")?;
88                        write_entity(val, f, last_indent + INDENT_INCREMENT, true)?;
89                        writeln!(f, ",")?;
90                    }
91                    write!(f, "{:last_indent$}}}", ' ')?;
92                }
93            }
94            Ok(())
95        }
96        write_entity(self, f, INDENT_INCREMENT, false)
97    }
98}
99
100/// Errors that can occur during parsing of bencoded data.
101#[derive(Debug, Error, Display)]
102pub enum ParseError {
103    EmptySource,
104    #[display("invalid prefix ({_0})")]
105    InvalidPrefix(u8),
106    NoIntegerPrefix,
107    NoIntegerEnd,
108    NoStringDelimeter,
109    #[display("invalid string length ({_0})")]
110    InvalidStringLength(usize),
111    NoListPrefix,
112    NoDictionaryPrefix,
113    #[display("{_0}")]
114    ExternalError(#[source] Box<dyn Error + Send + Sync>),
115}
116
117impl From<ParseIntError> for ParseError {
118    fn from(e: ParseIntError) -> Self {
119        ParseError::ExternalError(Box::new(e))
120    }
121}
122
123impl From<str::Utf8Error> for ParseError {
124    fn from(e: str::Utf8Error) -> Self {
125        ParseError::ExternalError(Box::new(e))
126    }
127}
128
129impl From<ParseError> for io::Error {
130    fn from(e: ParseError) -> Self {
131        io::Error::other(e)
132    }
133}
134
135/// Utility function for converting a bencoded dictionary to a more user-friendly representation.
136pub fn convert_dictionary(src: BTreeMap<Element, Element>) -> BTreeMap<String, Element> {
137    fn to_string_key((key, value): (Element, Element)) -> Option<(String, Element)> {
138        if let Element::ByteString(data) = key
139            && let Ok(text) = String::from_utf8(data)
140        {
141            Some((text, value))
142        } else {
143            None
144        }
145    }
146    src.into_iter().filter_map(to_string_key).collect()
147}
148
149const DELIMITER_STRING: u8 = b':';
150const PREFIX_INTEGER: u8 = b'i';
151const PREFIX_LIST: u8 = b'l';
152const PREFIX_DICTIONARY: u8 = b'd';
153const SUFFIX_COMMON: u8 = b'e';
154
155fn write_element(e: &Element, dest: &mut Vec<u8>) {
156    match e {
157        Element::Integer(number) => {
158            let _ = write!(dest, "{}{}{}", PREFIX_INTEGER as char, number, SUFFIX_COMMON as char);
159        }
160        Element::ByteString(data) => {
161            let _ = write!(dest, "{}{}", data.len(), DELIMITER_STRING as char);
162            dest.extend_from_slice(data);
163        }
164        Element::List(list) => {
165            dest.push(PREFIX_LIST);
166            for e in list {
167                write_element(e, dest);
168            }
169            dest.push(SUFFIX_COMMON);
170        }
171        Element::Dictionary(map) => {
172            dest.push(PREFIX_DICTIONARY);
173            for (key, value) in map {
174                write_element(key, dest);
175                write_element(value, dest);
176            }
177            dest.push(SUFFIX_COMMON);
178        }
179    };
180}
181
182fn read_element(src: &[u8]) -> Result<(Element, &[u8]), ParseError> {
183    let first_byte = src.first().ok_or(ParseError::EmptySource)?;
184    match *first_byte {
185        b'0'..=b'9' => read_string(src),
186        PREFIX_INTEGER => read_integer(src),
187        PREFIX_LIST => read_list(src),
188        PREFIX_DICTIONARY => read_dictionary(src),
189        prefix => Err(ParseError::InvalidPrefix(prefix)),
190    }
191}
192
193fn split_once(src: &[u8], delimeter: u8) -> Option<(&[u8], &[u8])> {
194    let opt_index = src.iter().position(|b| *b == delimeter);
195    match opt_index {
196        Some(index) => {
197            let lhs = unsafe { src.get_unchecked(..index) };
198            let rhs = unsafe { src.get_unchecked(index + 1..) };
199            Some((lhs, rhs))
200        }
201        None => None,
202    }
203}
204
205fn read_integer(src: &[u8]) -> Result<(Element, &[u8]), ParseError> {
206    let rest = src.strip_prefix(&[PREFIX_INTEGER]).ok_or(ParseError::NoIntegerPrefix)?;
207
208    let (number_data, rest) = split_once(rest, SUFFIX_COMMON).ok_or(ParseError::NoIntegerEnd)?;
209    let number_text = str::from_utf8(number_data)?;
210    let number = number_text.parse::<i64>()?;
211
212    Ok((Element::Integer(number), rest))
213}
214
215fn read_string(src: &[u8]) -> Result<(Element, &[u8]), ParseError> {
216    let (size_data, rest) =
217        split_once(src, DELIMITER_STRING).ok_or(ParseError::NoStringDelimeter)?;
218    let size_text = str::from_utf8(size_data)?;
219    let size = size_text.parse::<usize>()?;
220
221    let data = rest.get(..size).ok_or(ParseError::InvalidStringLength(size))?;
222    let rest = unsafe { rest.get_unchecked(size..) };
223
224    Ok((Element::ByteString(Vec::from(data)), rest))
225}
226
227fn read_list(src: &[u8]) -> Result<(Element, &[u8]), ParseError> {
228    let mut rest = src.strip_prefix(&[PREFIX_LIST]).ok_or(ParseError::NoListPrefix)?;
229
230    let mut list = Vec::new();
231    while !rest.starts_with(&[SUFFIX_COMMON]) {
232        let (entity, new_rest) = read_element(rest)?;
233        list.push(entity);
234        rest = new_rest;
235    }
236    Ok((Element::List(list), unsafe { rest.get_unchecked(1..) }))
237}
238
239fn read_dictionary(src: &[u8]) -> Result<(Element, &[u8]), ParseError> {
240    let mut rest = src.strip_prefix(&[PREFIX_DICTIONARY]).ok_or(ParseError::NoDictionaryPrefix)?;
241
242    let mut map = BTreeMap::new();
243    while !rest.starts_with(&[SUFFIX_COMMON]) {
244        let (key, new_rest) = read_string(rest)?;
245        rest = new_rest;
246
247        let (value, new_rest) = read_element(rest)?;
248        rest = new_rest;
249
250        map.insert(key, value);
251    }
252    Ok((Element::Dictionary(map), unsafe { rest.get_unchecked(1..) }))
253}
254
255#[allow(clippy::get_first)]
256#[cfg(test)]
257mod tests {
258    use super::*;
259
260    #[test]
261    fn test_decode_and_encode_negative_integer() {
262        let input = b"i-42e";
263
264        let parsed = read_integer(input);
265        assert!(parsed.is_ok(), "Error: {:?}", parsed.err());
266
267        let (entity, rest) = parsed.unwrap();
268        assert_eq!(Element::Integer(-42), entity);
269        assert!(rest.is_empty());
270
271        assert_eq!(input, entity.encode().as_slice());
272    }
273
274    #[test]
275    fn test_decode_invalid_integer() {
276        let input = b"i0_0e";
277
278        let parsed = read_integer(input);
279        assert!(parsed.is_err());
280
281        if let ParseError::ExternalError(msg) = parsed.err().unwrap() {
282            assert_eq!("invalid digit found in string", format!("{msg}"));
283        } else {
284            panic!("Wrong error type");
285        }
286    }
287
288    #[test]
289    fn test_decode_non_utf8_integer() {
290        let input = [PREFIX_INTEGER, 200, 201, 202, SUFFIX_COMMON];
291
292        let parsed = read_integer(&input);
293        assert!(parsed.is_err());
294
295        if let ParseError::ExternalError(msg) = parsed.err().unwrap() {
296            assert_eq!("invalid utf-8 sequence of 1 bytes from index 0", format!("{msg}"));
297        } else {
298            panic!("Wrong error type");
299        }
300    }
301
302    #[test]
303    fn test_decode_and_encode_simple_string() {
304        let input = b"15:A simple string";
305
306        let parsed = read_string(input);
307        assert!(parsed.is_ok(), "Error: {:?}", parsed.err());
308
309        let (entity, rest) = parsed.unwrap();
310        assert_eq!(Element::ByteString(Vec::from(b"A simple string".as_slice())), entity);
311        assert!(rest.is_empty());
312
313        assert_eq!(input, entity.encode().as_slice());
314    }
315
316    #[test]
317    fn test_decode_and_encode_non_ascii_string() {
318        let input = "22:Добрый день!";
319
320        let parsed = read_string(input.as_bytes());
321        assert!(parsed.is_ok(), "Error: {:?}", parsed.err());
322
323        let (entity, rest) = parsed.unwrap();
324        assert_eq!(Element::ByteString(Vec::from("Добрый день!".as_bytes())), entity);
325        assert!(rest.is_empty());
326
327        assert_eq!(input.as_bytes(), entity.encode().as_slice());
328    }
329
330    #[test]
331    fn test_decode_and_encode_binary_string() {
332        let input = [b'4', b':', 0xf1, 0xf2, 0xf3, 0xf4];
333
334        let parsed = read_string(&input);
335        assert!(parsed.is_ok(), "Error: {:?}", parsed.err());
336
337        let (entity, rest) = parsed.unwrap();
338        assert_eq!(Element::ByteString(Vec::from([0xf1, 0xf2, 0xf3, 0xf4].as_slice())), entity);
339        assert!(rest.is_empty());
340
341        assert_eq!(&input, entity.encode().as_slice());
342    }
343
344    #[test]
345    fn test_decode_string_with_invalid_length() {
346        let input = [b'9', b'2', b':', 0xf1, 0xf2, 0xf3, 0xf4];
347
348        let parsed = read_string(&input);
349        assert!(parsed.is_err());
350        assert!(matches!(parsed.err().unwrap(), ParseError::InvalidStringLength(_)));
351    }
352
353    #[test]
354    fn test_decode_and_encode_simple_list() {
355        let input = "li-42ei42e15:A simple stringe";
356
357        let parsed = read_list(input.as_bytes());
358        assert!(parsed.is_ok(), "Error: {:?}", parsed.err());
359
360        let (entity, rest) = parsed.unwrap();
361        assert!(rest.is_empty());
362
363        if let Element::List(ref list) = entity {
364            assert_eq!(3, list.len());
365            assert_eq!(Element::Integer(-42), *list.get(0).unwrap());
366            assert_eq!(Element::Integer(42), *list.get(1).unwrap());
367            assert_eq!(
368                Element::ByteString(Vec::from("A simple string".as_bytes())),
369                *list.get(2).unwrap()
370            );
371        } else {
372            panic!("Not a list");
373        }
374
375        assert_eq!(input.as_bytes(), entity.encode().as_slice());
376    }
377
378    #[test]
379    fn test_decode_list_without_end_postfix() {
380        let input = "li-42ei42e15:A simple string";
381
382        let parsed = read_list(input.as_bytes());
383        assert!(parsed.is_err());
384        assert!(matches!(parsed.err().unwrap(), ParseError::EmptySource));
385    }
386
387    #[test]
388    fn test_decode_and_encode_list_with_binary_string() {
389        let input = {
390            let start = b"li42e";
391            let end = [b'4', b':', 0xf1, 0xf2, 0xf3, 0xf4, b'e'];
392            let mut buf = Vec::<u8>::new();
393            buf.write_all(start).unwrap();
394            buf.write_all(&end).unwrap();
395            buf
396        };
397
398        let parsed = read_list(&input);
399        assert!(parsed.is_ok(), "Error: {:?}", parsed.err());
400
401        let (entity, rest) = parsed.unwrap();
402        assert!(rest.is_empty());
403
404        if let Element::List(ref list) = entity {
405            assert_eq!(2, list.len());
406            assert_eq!(Element::Integer(42), *list.get(0).unwrap());
407            assert_eq!(
408                Element::ByteString(Vec::from([0xf1, 0xf2, 0xf3, 0xf4].as_slice())),
409                *list.get(1).unwrap()
410            );
411        } else {
412            panic!("Not a list");
413        }
414
415        assert_eq!(&input, entity.encode().as_slice());
416    }
417
418    #[test]
419    fn test_decode_and_encode_simple_dictionary() {
420        let input = "d8:announce41:http://tracker.trackerfix.com:80/announcee";
421
422        let parsed = read_dictionary(input.as_bytes());
423        assert!(parsed.is_ok(), "Error: {:?}", parsed.err());
424
425        let (entity, rest) = parsed.unwrap();
426        assert!(rest.is_empty());
427        if let Element::Dictionary(ref map) = entity {
428            assert_eq!(1, map.len());
429            let (key, value) = map.iter().next().unwrap();
430            assert_eq!(Element::ByteString(Vec::from("announce".as_bytes())), *key);
431            assert_eq!(
432                Element::ByteString(Vec::from(
433                    "http://tracker.trackerfix.com:80/announce".as_bytes()
434                )),
435                *value
436            );
437        } else {
438            panic!("Not a dictionary");
439        }
440
441        assert_eq!(input.as_bytes(), entity.encode().as_slice());
442    }
443
444    #[test]
445    fn test_decode_dictionary_with_appended_data() {
446        let input = "d8:msg_typei1e5:piecei0e10:total_sizei34256eexxxxxxxx";
447
448        let parsed = Element::from_bytes(input.as_bytes()).unwrap();
449
450        if let Element::Dictionary(map) = parsed {
451            let mut it = map.into_iter();
452
453            let (key, value) = it.next().unwrap();
454            assert_eq!(Element::from("msg_type"), key);
455            assert_eq!(Element::Integer(1), value);
456
457            let (key, value) = it.next().unwrap();
458            assert_eq!(Element::from("piece"), key);
459            assert_eq!(Element::Integer(0), value);
460
461            let (key, value) = it.next().unwrap();
462            assert_eq!(Element::from("total_size"), key);
463            assert_eq!(Element::Integer(34256), value);
464
465            assert!(it.next().is_none());
466        } else {
467            panic!("Not a dictionary");
468        }
469    }
470
471    #[test]
472    fn test_decode_and_encode_real_dictionary() {
473        let input = "d8:announce41:http://tracker.trackerfix.com:80/announce13:announce-listll41:http://tracker.trackerfix.com:80/announceel30:udp://9.rarbg.me:2720/announceel30:udp://9.rarbg.to:2740/announceel42:udp://tracker.fatkhoala.org:13780/announceel44:udp://tracker.tallpenguin.org:15760/announceee7:comment40:Torrent downloaded from https://rarbg.to10:created by5:RARBG13:creation datei1629718368e4:infod5:filesld6:lengthi30e4:pathl9:RARBG.txteed6:lengthi99e4:pathl23:RARBG_DO_NOT_MIRROR.exeeed6:lengthi66667e4:pathl4:Subs13:10_French.srteed6:lengthi67729e4:pathl4:Subs13:11_German.srteed6:lengthi98430e4:pathl4:Subs12:12_Greek.srteed6:lengthi89001e4:pathl4:Subs13:13_Hebrew.srteed6:lengthi66729e4:pathl4:Subs10:14_hrv.srteed6:lengthi69251e4:pathl4:Subs16:15_Hungarian.srteed6:lengthi67897e4:pathl4:Subs17:16_Indonesian.srteed6:lengthi67035e4:pathl4:Subs14:17_Italian.srteed6:lengthi68310e4:pathl4:Subs15:18_Japanese.srteed6:lengthi79479e4:pathl4:Subs13:19_Korean.srteed6:lengthi67367e4:pathl4:Subs10:20_may.srteed6:lengthi63337e4:pathl4:Subs13:21_Bokmal.srteed6:lengthi68715e4:pathl4:Subs13:22_Polish.srteed6:lengthi67838e4:pathl4:Subs17:23_Portuguese.srteed6:lengthi69077e4:pathl4:Subs17:24_Portuguese.srteed6:lengthi70967e4:pathl4:Subs15:25_Romanian.srteed6:lengthi90311e4:pathl4:Subs14:26_Russian.srteed6:lengthi67143e4:pathl4:Subs14:27_Spanish.srteed6:lengthi67068e4:pathl4:Subs14:28_Spanish.srteed6:lengthi63229e4:pathl4:Subs14:29_Swedish.srteed6:lengthi97509e4:pathl4:Subs12:2_Arabic.srteed6:lengthi126859e4:pathl4:Subs11:30_Thai.srteed6:lengthi69519e4:pathl4:Subs14:31_Turkish.srteed6:lengthi87216e4:pathl4:Subs10:32_ukr.srteed6:lengthi86745e4:pathl4:Subs17:33_Vietnamese.srteed6:lengthi71908e4:pathl4:Subs13:3_Chinese.srteed6:lengthi71949e4:pathl4:Subs13:4_Chinese.srteed6:lengthi69054e4:pathl4:Subs11:5_Czech.srteed6:lengthi64987e4:pathl4:Subs12:6_Danish.srteed6:lengthi60512e4:pathl4:Subs11:7_Dutch.srteed6:lengthi81102e4:pathl4:Subs13:8_English.srteed6:lengthi62658e4:pathl4:Subs13:9_Finnish.srteed6:lengthi1397575464e4:pathl66:The.Witcher.Nightmare.of.the.Wolf.2021.1080p.WEBRip.x265-RARBG.mp4eee4:name62:The.Witcher.Nightmare.of.the.Wolf.2021.1080p.WEBRip.x265-RARBG12:piece lengthi2097152eee";
474
475        let parsed = read_dictionary(input.as_bytes());
476        assert!(parsed.is_ok(), "Error: {:?}", parsed.err());
477
478        let entity = parsed.unwrap();
479        match entity.0 {
480            Element::Dictionary(_) => (),
481            _ => panic!(),
482        };
483
484        assert_eq!(input.as_bytes(), entity.0.encode().as_slice());
485    }
486
487    #[test]
488    fn test_format_bencode() {
489        #[rustfmt::skip]
490        let expected = 
491r#"   {
492      "announce": "http://tracker.trackerfix.com:80/announce",
493      "announce-list": [
494         [
495            "http://tracker.trackerfix.com:80/announce",
496         ],
497         [
498            "udp://9.rarbg.me:2720/announce",
499         ],
500         [
501            "udp://9.rarbg.to:2740/announce",
502         ],
503         [
504            "udp://tracker.fatkhoala.org:13780/announce",
505         ],
506         [
507            "udp://tracker.tallpenguin.org:15760/announce",
508         ],
509      ],
510      "comment": "Torrent downloaded from https://rarbg.to",
511      "created by": "RARBG",
512      "creation date": 1629718368,
513      "info": {
514         "files": [
515            {
516               "length": 30,
517               "path": [
518                  "RARBG.txt",
519               ],
520            },
521            {
522               "length": 99,
523               "path": [
524                  "RARBG_DO_NOT_MIRROR.exe",
525               ],
526            },
527            {
528               "length": 66667,
529               "path": [
530                  "Subs",
531                  "10_French.srt",
532               ],
533            },
534            {
535               "length": 67729,
536               "path": [
537                  "Subs",
538                  "11_German.srt",
539               ],
540            },
541            {
542               "length": 98430,
543               "path": [
544                  "Subs",
545                  "12_Greek.srt",
546               ],
547            },
548            {
549               "length": 89001,
550               "path": [
551                  "Subs",
552                  "13_Hebrew.srt",
553               ],
554            },
555            {
556               "length": 66729,
557               "path": [
558                  "Subs",
559                  "14_hrv.srt",
560               ],
561            },
562            {
563               "length": 69251,
564               "path": [
565                  "Subs",
566                  "15_Hungarian.srt",
567               ],
568            },
569            {
570               "length": 67897,
571               "path": [
572                  "Subs",
573                  "16_Indonesian.srt",
574               ],
575            },
576            {
577               "length": 67035,
578               "path": [
579                  "Subs",
580                  "17_Italian.srt",
581               ],
582            },
583            {
584               "length": 68310,
585               "path": [
586                  "Subs",
587                  "18_Japanese.srt",
588               ],
589            },
590            {
591               "length": 79479,
592               "path": [
593                  "Subs",
594                  "19_Korean.srt",
595               ],
596            },
597            {
598               "length": 67367,
599               "path": [
600                  "Subs",
601                  "20_may.srt",
602               ],
603            },
604            {
605               "length": 63337,
606               "path": [
607                  "Subs",
608                  "21_Bokmal.srt",
609               ],
610            },
611            {
612               "length": 68715,
613               "path": [
614                  "Subs",
615                  "22_Polish.srt",
616               ],
617            },
618            {
619               "length": 67838,
620               "path": [
621                  "Subs",
622                  "23_Portuguese.srt",
623               ],
624            },
625            {
626               "length": 69077,
627               "path": [
628                  "Subs",
629                  "24_Portuguese.srt",
630               ],
631            },
632            {
633               "length": 70967,
634               "path": [
635                  "Subs",
636                  "25_Romanian.srt",
637               ],
638            },
639            {
640               "length": 90311,
641               "path": [
642                  "Subs",
643                  "26_Russian.srt",
644               ],
645            },
646            {
647               "length": 67143,
648               "path": [
649                  "Subs",
650                  "27_Spanish.srt",
651               ],
652            },
653            {
654               "length": 67068,
655               "path": [
656                  "Subs",
657                  "28_Spanish.srt",
658               ],
659            },
660            {
661               "length": 63229,
662               "path": [
663                  "Subs",
664                  "29_Swedish.srt",
665               ],
666            },
667            {
668               "length": 97509,
669               "path": [
670                  "Subs",
671                  "2_Arabic.srt",
672               ],
673            },
674            {
675               "length": 126859,
676               "path": [
677                  "Subs",
678                  "30_Thai.srt",
679               ],
680            },
681            {
682               "length": 69519,
683               "path": [
684                  "Subs",
685                  "31_Turkish.srt",
686               ],
687            },
688            {
689               "length": 87216,
690               "path": [
691                  "Subs",
692                  "32_ukr.srt",
693               ],
694            },
695            {
696               "length": 86745,
697               "path": [
698                  "Subs",
699                  "33_Vietnamese.srt",
700               ],
701            },
702            {
703               "length": 71908,
704               "path": [
705                  "Subs",
706                  "3_Chinese.srt",
707               ],
708            },
709            {
710               "length": 71949,
711               "path": [
712                  "Subs",
713                  "4_Chinese.srt",
714               ],
715            },
716            {
717               "length": 69054,
718               "path": [
719                  "Subs",
720                  "5_Czech.srt",
721               ],
722            },
723            {
724               "length": 64987,
725               "path": [
726                  "Subs",
727                  "6_Danish.srt",
728               ],
729            },
730            {
731               "length": 60512,
732               "path": [
733                  "Subs",
734                  "7_Dutch.srt",
735               ],
736            },
737            {
738               "length": 81102,
739               "path": [
740                  "Subs",
741                  "8_English.srt",
742               ],
743            },
744            {
745               "length": 62658,
746               "path": [
747                  "Subs",
748                  "9_Finnish.srt",
749               ],
750            },
751            {
752               "length": 1397575464,
753               "path": [
754                  "The.Witcher.Nightmare.of.the.Wolf.2021.1080p.WEBRip.x265-RARBG.mp4",
755               ],
756            },
757         ],
758         "name": "The.Witcher.Nightmare.of.the.Wolf.2021.1080p.WEBRip.x265-RARBG",
759         "piece length": 2097152,
760      },
761   }"#;
762
763        let input = "d8:announce41:http://tracker.trackerfix.com:80/announce13:announce-listll41:http://tracker.trackerfix.com:80/announceel30:udp://9.rarbg.me:2720/announceel30:udp://9.rarbg.to:2740/announceel42:udp://tracker.fatkhoala.org:13780/announceel44:udp://tracker.tallpenguin.org:15760/announceee7:comment40:Torrent downloaded from https://rarbg.to10:created by5:RARBG13:creation datei1629718368e4:infod5:filesld6:lengthi30e4:pathl9:RARBG.txteed6:lengthi99e4:pathl23:RARBG_DO_NOT_MIRROR.exeeed6:lengthi66667e4:pathl4:Subs13:10_French.srteed6:lengthi67729e4:pathl4:Subs13:11_German.srteed6:lengthi98430e4:pathl4:Subs12:12_Greek.srteed6:lengthi89001e4:pathl4:Subs13:13_Hebrew.srteed6:lengthi66729e4:pathl4:Subs10:14_hrv.srteed6:lengthi69251e4:pathl4:Subs16:15_Hungarian.srteed6:lengthi67897e4:pathl4:Subs17:16_Indonesian.srteed6:lengthi67035e4:pathl4:Subs14:17_Italian.srteed6:lengthi68310e4:pathl4:Subs15:18_Japanese.srteed6:lengthi79479e4:pathl4:Subs13:19_Korean.srteed6:lengthi67367e4:pathl4:Subs10:20_may.srteed6:lengthi63337e4:pathl4:Subs13:21_Bokmal.srteed6:lengthi68715e4:pathl4:Subs13:22_Polish.srteed6:lengthi67838e4:pathl4:Subs17:23_Portuguese.srteed6:lengthi69077e4:pathl4:Subs17:24_Portuguese.srteed6:lengthi70967e4:pathl4:Subs15:25_Romanian.srteed6:lengthi90311e4:pathl4:Subs14:26_Russian.srteed6:lengthi67143e4:pathl4:Subs14:27_Spanish.srteed6:lengthi67068e4:pathl4:Subs14:28_Spanish.srteed6:lengthi63229e4:pathl4:Subs14:29_Swedish.srteed6:lengthi97509e4:pathl4:Subs12:2_Arabic.srteed6:lengthi126859e4:pathl4:Subs11:30_Thai.srteed6:lengthi69519e4:pathl4:Subs14:31_Turkish.srteed6:lengthi87216e4:pathl4:Subs10:32_ukr.srteed6:lengthi86745e4:pathl4:Subs17:33_Vietnamese.srteed6:lengthi71908e4:pathl4:Subs13:3_Chinese.srteed6:lengthi71949e4:pathl4:Subs13:4_Chinese.srteed6:lengthi69054e4:pathl4:Subs11:5_Czech.srteed6:lengthi64987e4:pathl4:Subs12:6_Danish.srteed6:lengthi60512e4:pathl4:Subs11:7_Dutch.srteed6:lengthi81102e4:pathl4:Subs13:8_English.srteed6:lengthi62658e4:pathl4:Subs13:9_Finnish.srteed6:lengthi1397575464e4:pathl66:The.Witcher.Nightmare.of.the.Wolf.2021.1080p.WEBRip.x265-RARBG.mp4eee4:name62:The.Witcher.Nightmare.of.the.Wolf.2021.1080p.WEBRip.x265-RARBG12:piece lengthi2097152eee";
764
765        let parsed = read_dictionary(input.as_bytes());
766        assert!(parsed.is_ok(), "Error: {:?}", parsed.err());
767
768        let entity = parsed.unwrap().0;
769        assert_eq!(expected, format!("{entity}"), "\n{entity}\n");
770    }
771}