1use core::str;
2use std::{collections::HashMap, process::exit};
3
4
5use crate::{errors::ParseError, get_hash};
6
7const INTEGER_START: u8 = 0x69; const STRING_DELIM: u8 = 0x3A; const DICTIONARY_START: u8 = 0x64; const LIST_START: u8 = 0x6C; const END_OF_TYPE: u8 = 0x65; pub type Peers = Vec<((u8, u8, u8, u8), u16)>;
14
15#[derive(Debug, PartialEq)]
16pub enum BencodeTypes {
17 String(String),
18 Integer(u64),
19 List(Vec<BencodeTypes>),
20 Dict(HashMap<String, BencodeTypes>),
21 InfoHash([u8; 20]),
22 Pieces(Vec<[u8; 20]>),
23 PeersCompact(Peers),
24}
25
26fn parse_to_utf8(slice: &[u8]) -> Result<String, ParseError> {
27 let string_slice = str::from_utf8(slice)?;
28 Ok(string_slice.to_string())
29}
30
31fn parse_to_usize(slice: &[u8]) -> Result<usize, ParseError> {
32 let string = parse_to_utf8(slice)?;
33 Ok(string.parse()?)
34}
35
36fn get_string_len(pointer: &mut usize, buf: &Vec<u8>) -> Result<usize, ParseError> {
37 let mut temp = Vec::new();
38
39 while buf[*pointer] != STRING_DELIM {
41 temp.push(buf[*pointer]);
42 *pointer += 1;
43 }
44
45 *pointer += 1;
47
48 if temp.len() == 1 && temp[0] == 48 {
49 return Ok(0);
50 }
51
52 Ok(parse_to_usize(&temp)?)
53}
54
55pub fn decode_string(pointer: &mut usize, buf: &Vec<u8>) -> Result<String, ParseError> {
56 let string_len = get_string_len(pointer, buf)?;
57
58 if string_len == 0 {
59 return Ok("".to_string());
60 }
61
62 let string_len = string_len + *pointer;
63 let slice: &[u8] = &buf[*pointer..string_len];
64
65 *pointer = string_len;
67
68 Ok(parse_to_utf8(slice)?)
69}
70
71pub fn decode_int(pointer: &mut usize, buf: &Vec<u8>) -> Result<u64, ParseError> {
72 let mut int_bytes = Vec::new();
73
74 *pointer += 1;
76
77 while buf[*pointer] != END_OF_TYPE {
78 int_bytes.push(buf[*pointer]);
79 *pointer += 1;
80 }
81
82 *pointer += 1;
84
85 Ok(parse_to_usize(&int_bytes)? as u64)
86}
87
88pub fn decode_list(pointer: &mut usize, buf: &Vec<u8>) -> Result<Vec<BencodeTypes>, ParseError> {
89 let mut list: Vec<BencodeTypes> = Vec::new();
90
91 *pointer += 1;
93
94 while buf[*pointer] != END_OF_TYPE {
95 list.push(match buf[*pointer] {
96 n if n.is_ascii_digit() => BencodeTypes::String(decode_string(pointer, buf)?),
97 INTEGER_START => BencodeTypes::Integer(decode_int(pointer, buf)?),
98 LIST_START => BencodeTypes::List(decode_list(pointer, buf)?),
99 DICTIONARY_START => BencodeTypes::Dict(decode_dict(pointer, buf)?),
100 _ => todo!(),
101 })
102 }
103
104 *pointer += 1;
106
107 Ok(list)
108}
109
110pub fn decode_pieces(pointer: &mut usize, buf: &Vec<u8>) -> Result<Vec<[u8; 20]>, ParseError> {
111 let pieces_len = get_string_len(pointer, buf)?;
112
113 let pieces_len = pieces_len + *pointer;
114
115 let pieces_vec: Vec<[u8; 20]> = buf[*pointer..pieces_len]
116 .chunks_exact(20)
117 .map(|h| match h.try_into() {
118 Ok(h) => h,
119 Err(e) => {
120 println!("bad pieces array! e: {e}");
121 exit(1);
122 }
123 })
124 .collect();
125
126 *pointer = pieces_len;
128
129 Ok(pieces_vec)
130}
131
132fn decode_peers(pointer: &mut usize, buf: &Vec<u8>) -> Result<BencodeTypes, ParseError> {
133 if buf[*pointer] == LIST_START {
134 let decoded = decode_list(pointer, buf)?;
135 return Ok(BencodeTypes::List(decoded));
136 }
137
138 let peers_len = get_string_len(pointer, buf)?;
139
140 let peers_len = peers_len + *pointer;
141
142 let peers_vec = buf[*pointer..peers_len]
143 .chunks_exact(6)
144 .map(|item| {
145 (
146 (item[0], item[1], item[2], item[3]),
147 u16::from_be_bytes([item[4], item[5]]),
148 )
149 })
150 .collect();
151
152 *pointer = peers_len;
154
155 Ok(BencodeTypes::PeersCompact(peers_vec))
156}
157
158pub fn decode_dict(
159 pointer: &mut usize,
160 buf: &Vec<u8>,
161) -> Result<HashMap<String, BencodeTypes>, ParseError> {
162 if buf.len() == 0 {
163 return Err(ParseError::BadFile);
164 }
165
166 let mut dict: HashMap<String, BencodeTypes> = HashMap::new();
167
168 *pointer += 1;
170
171 let mut is_key = true;
172 let mut temp_key = String::new();
173 let mut info_hash_start: usize = 0;
174
175 while buf[*pointer] != END_OF_TYPE && *pointer != buf.len() {
176 if is_key {
177 temp_key = decode_string(pointer, buf)?;
178 if temp_key == "info" {
179 info_hash_start = *pointer;
180 }
181 is_key = !is_key;
182 continue;
183 }
184
185 let parsed = match buf[*pointer] {
186 n if n.is_ascii_digit() && temp_key == "pieces" => {
187 BencodeTypes::Pieces(decode_pieces(pointer, buf)?)
188 }
189 n if n.is_ascii_digit() && temp_key == "peers" => decode_peers(pointer, buf)?,
190 n if n.is_ascii_digit() => BencodeTypes::String(decode_string(pointer, buf)?),
191 INTEGER_START => BencodeTypes::Integer(decode_int(pointer, buf)?),
192 LIST_START => BencodeTypes::List(decode_list(pointer, buf)?),
193 DICTIONARY_START => BencodeTypes::Dict(decode_dict(pointer, buf)?),
194 _ => todo!(),
195 };
196
197 dict.insert(temp_key.clone(), parsed);
198 is_key = !is_key;
199 }
200
201 if info_hash_start != 0 {
203 let slice = &buf[info_hash_start..*pointer];
204 let hash = get_hash(slice)?;
205 dict.insert(String::from("info_hash"), BencodeTypes::InfoHash(hash));
206 }
207
208 *pointer += 1;
210
211 Ok(dict)
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217
218 #[test]
219 fn decodes_string_and_advances_pointer() {
220 let test_vec = b"11:HelloWorld!".to_vec();
221 let mut pointer = 0;
222 let result = decode_string(&mut pointer, &test_vec).unwrap();
223
224 assert_eq!(String::from("HelloWorld!"), result);
225 assert_eq!(pointer, 14);
226 }
227
228 #[test]
229 fn decodes_int_and_advances_pointer() {
230 let test_vec = b"i5657e".to_vec();
231 let mut pointer = 0;
232 let result = decode_int(&mut pointer, &test_vec).unwrap();
233
234 assert_eq!(5657 as u64, result);
235 assert_eq!(pointer, 6);
236 }
237
238 #[test]
239 fn decodes_list_and_advances_pointer() {
240 let test_vec =
241 b"l11:HelloWorld!i5657el11:HelloWorld!i5657eed3:bar4:spam3:fooi42eee".to_vec();
242 let mut pointer = 0;
243 let result = decode_list(&mut pointer, &test_vec).unwrap();
244
245 let string = String::from("HelloWorld!");
246 let bar = String::from("bar");
247 let spam = String::from("spam");
248 let foo = String::from("foo");
249 let int: u64 = 5657;
250
251 let dict: HashMap<String, BencodeTypes> = HashMap::from([
252 (bar.clone(), BencodeTypes::String(spam.clone())),
253 (foo.clone(), BencodeTypes::Integer(42)),
254 ]);
255
256 assert_eq!(
257 vec![
258 BencodeTypes::String(string.clone()),
259 BencodeTypes::Integer(int.clone()),
260 BencodeTypes::List(vec![
261 BencodeTypes::String(string.clone()),
262 BencodeTypes::Integer(int.clone()),
263 ]),
264 BencodeTypes::Dict(dict),
265 ],
266 result,
267 );
268 assert_eq!(pointer, 66);
269 }
270
271 #[test]
272 fn decodes_dict_and_advances_pointer() {
273 let test_vec = b"d11:HelloWorld!i42e4:listll4:testel4:testeee".to_vec();
274 let mut pointer = 0;
275 let result = decode_dict(&mut pointer, &test_vec).unwrap();
276
277 let string = String::from("HelloWorld!");
278 let test = String::from("test");
279 let list = String::from("list");
280 let int: u64 = 42;
281
282 let dict: HashMap<String, BencodeTypes> = HashMap::from([
283 (string.clone(), BencodeTypes::Integer(int)),
284 (
285 list.clone(),
286 BencodeTypes::List(vec![
287 BencodeTypes::List(vec![BencodeTypes::String(test.clone())]),
288 BencodeTypes::List(vec![BencodeTypes::String(test.clone())]),
289 ]),
290 ),
291 ]);
292
293 assert_eq!(dict, result);
294 assert_eq!(pointer, 44);
295 }
296}