[bencode] Decode dicts

This commit is contained in:
Fabian 2024-07-22 22:05:59 +02:00
parent e2b2f8efca
commit f9ed2388a2

View File

@ -109,8 +109,8 @@ impl Bencode {
Ok((result, end_pos + 1)) Ok((result, end_pos + 1))
}, },
BencodeType::Dict => { BencodeType::Dict => {
let result = Self::dummy(to_decode)?; let (result, end_pos) = Self::decode_dict(to_decode)?;
Ok((result, end_decoded)) Ok((result, end_pos + 1))
}, },
} }
} }
@ -146,8 +146,25 @@ impl Bencode {
Ok((Bencode::List(result), decoded_pos)) Ok((Bencode::List(result), decoded_pos))
} }
fn dummy(_input: &[u8]) -> Result<Bencode> { fn decode_dict(input: &[u8]) -> Result<(Bencode, usize)> {
Ok(Bencode::Integer(42)) 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"))),
]))
);
} }
} }