From f9ed2388a2fef2423712f66adc5d2a2abb34ffde Mon Sep 17 00:00:00 2001 From: Faerbit Date: Mon, 22 Jul 2024 22:05:59 +0200 Subject: [PATCH] [bencode] Decode dicts --- src/bencode.rs | 122 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 118 insertions(+), 4 deletions(-) diff --git a/src/bencode.rs b/src/bencode.rs index 254d74d..8502439 100644 --- a/src/bencode.rs +++ b/src/bencode.rs @@ -109,8 +109,8 @@ impl Bencode { Ok((result, end_pos + 1)) }, BencodeType::Dict => { - let result = Self::dummy(to_decode)?; - Ok((result, end_decoded)) + let (result, end_pos) = Self::decode_dict(to_decode)?; + Ok((result, end_pos + 1)) }, } } @@ -146,8 +146,25 @@ impl Bencode { Ok((Bencode::List(result), decoded_pos)) } - fn dummy(_input: &[u8]) -> Result { - Ok(Bencode::Integer(42)) + fn decode_dict(input: &[u8]) -> Result<(Bencode, usize)> { + let mut result = HashMap::new(); + let mut decoded_pos = 0; + loop { + if decoded_pos >= input.len() { + return Err(anyhow!("Unfinished dict. Could not find terminating character 'e'")) + } + if input[decoded_pos] == 'e' as u8 { + break; + } + let (Bencode::Bytes(key_result), end_pos) = Self::decode_type(&input[decoded_pos..])? else { + return Err(anyhow!("Type of dictionary key not Bytes")) + }; + decoded_pos += end_pos + 1; + let (value_result, end_pos) = Self::decode_type(&input[decoded_pos..])?; + result.insert(key_result, value_result); + decoded_pos += end_pos + 1; + } + Ok((Bencode::Dict(result), decoded_pos)) } } @@ -349,6 +366,103 @@ mod tests { ]), ]), ); + let str = format!("ll{}{}ed{}{}{}{}ee", test_encode_bytes("hallo"), "i42e", test_encode_bytes("foo"), "i23e", test_encode_bytes("bar"), test_encode_bytes("baz")); + assert_eq!(Bencode::decode(&str).unwrap(), + Bencode::List(vec![ + Bencode::List(vec![ + Bencode::Bytes(ByteString::from_str("hallo")), + Bencode::Integer(42), + ]), + Bencode::Dict(HashMap::from([ + (ByteString::from_str("foo"), Bencode::Integer(23)), + (ByteString::from_str("bar"), Bencode::Bytes(ByteString::from_str("baz"))), + ])), + ]), + ); + } + #[test] + fn test_dict() { + assert_eq!(Bencode::decode_dict( + ("e").as_bytes()).unwrap(), + (Bencode::Dict(HashMap::new()), 0) + ); + let str = "3:fooi42ee"; + assert_eq!(Bencode::decode_dict( + str.as_bytes()).unwrap(), + (Bencode::Dict(HashMap::from([ + (ByteString::from_str("foo"), Bencode::Integer(42)), + ])), str.len() - 1) + ); + let str = "3:foo3:bare"; + assert_eq!(Bencode::decode_dict( + str.as_bytes()).unwrap(), + (Bencode::Dict(HashMap::from([ + (ByteString::from_str("foo"), Bencode::Bytes(ByteString::from_str("bar"))), + ])), str.len() - 1) + ); + let str = "3:fooi42e3:bar3:baze"; + assert_eq!(Bencode::decode_dict( + str.as_bytes()).unwrap(), + (Bencode::Dict(HashMap::from([ + (ByteString::from_str("foo"), Bencode::Integer(42)), + (ByteString::from_str("bar"), Bencode::Bytes(ByteString::from_str("baz"))), + ])), str.len() - 1) + ); + let str = "3:fooli42ei17ee3:bar3:baze"; + assert_eq!(Bencode::decode_dict( + str.as_bytes()).unwrap(), + (Bencode::Dict(HashMap::from([ + (ByteString::from_str("foo"), Bencode::List( + vec![Bencode::Integer(42), Bencode::Integer(17)])), + (ByteString::from_str("bar"), Bencode::Bytes(ByteString::from_str("baz"))), + ])), str.len() - 1) + ); + } + + #[test] + fn test_dict_str() { + assert_eq!(Bencode::decode("de").unwrap(), + Bencode::Dict(HashMap::new()) + ); + let str = "d3:fooi42ee"; + assert_eq!(Bencode::decode(str).unwrap(), + Bencode::Dict(HashMap::from([ + (ByteString::from_str("foo"), Bencode::Integer(42)), + ])) + ); + let str = format!("d{}i42ee", test_encode_bytes("💩")); + assert_eq!(Bencode::decode(str.as_str()).unwrap(), + Bencode::Dict(HashMap::from([ + (ByteString::from_str("💩"), Bencode::Integer(42)), + ])) + ); + let str = "d3:foo3:bare"; + assert_eq!(Bencode::decode(str).unwrap(), + Bencode::Dict(HashMap::from([ + (ByteString::from_str("foo"), Bencode::Bytes(ByteString::from_str("bar"))), + ])) + ); + let str = "d3:fooi42e3:bar3:baze"; + assert_eq!(Bencode::decode(str).unwrap(), + Bencode::Dict(HashMap::from([ + (ByteString::from_str("foo"), Bencode::Integer(42)), + (ByteString::from_str("bar"), Bencode::Bytes(ByteString::from_str("baz"))), + ])) + ); + let str = "d3:fooli42ei17ee3:bar3:baze"; + assert_eq!(Bencode::decode(str).unwrap(), + Bencode::Dict(HashMap::from([ + (ByteString::from_str("foo"), Bencode::List( + vec![Bencode::Integer(42), Bencode::Integer(17)])), + (ByteString::from_str("bar"), Bencode::Bytes(ByteString::from_str("baz"))), + ])) + ); + let str = "d3:foo3:bare"; + assert_eq!(Bencode::decode(str).unwrap(), + Bencode::Dict(HashMap::from([ + (ByteString::from_str("foo"), Bencode::Bytes(ByteString::from_str("bar"))), + ])) + ); } }