chore: initial sanitized public snapshot
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
use super::bencode::BencodeValue;
|
||||
|
||||
/// Decodes a 40-character hexadecimal string into a fixed-width 20-byte array.
|
||||
pub(super) fn decode_hex_20_array(input: &str) -> Result<[u8; 20], String> {
|
||||
if input.len() != 40 {
|
||||
return Err(format!(
|
||||
"expected 40 hex characters for 20-byte info-hash, got {}",
|
||||
input.len()
|
||||
));
|
||||
}
|
||||
let mut out = [0_u8; 20];
|
||||
for (index, chunk) in input.as_bytes().chunks_exact(2).enumerate() {
|
||||
let hi = decode_hex_nibble(chunk[0])
|
||||
.ok_or_else(|| "info-hash contains non-hex characters".to_owned())?;
|
||||
let lo = decode_hex_nibble(chunk[1])
|
||||
.ok_or_else(|| "info-hash contains non-hex characters".to_owned())?;
|
||||
out[index] = (hi << 4) | lo;
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// Decodes one ASCII hexadecimal nibble.
|
||||
const fn decode_hex_nibble(byte: u8) -> Option<u8> {
|
||||
match byte {
|
||||
b'0'..=b'9' => Some(byte - b'0'),
|
||||
b'a'..=b'f' => Some(byte - b'a' + 10),
|
||||
b'A'..=b'F' => Some(byte - b'A' + 10),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Decodes torrent byte strings into owned lossy UTF-8 text.
|
||||
pub(super) fn bytes_to_string(bytes: &[u8]) -> String {
|
||||
String::from_utf8_lossy(bytes).into_owned()
|
||||
}
|
||||
|
||||
/// Converts one torrent bencode value into human-readable string form.
|
||||
pub(super) fn value_to_string(value: &BencodeValue) -> String {
|
||||
match value {
|
||||
BencodeValue::Bytes(bytes) => bytes_to_string(bytes),
|
||||
BencodeValue::Int(value) => value.to_string(),
|
||||
BencodeValue::List(values) => values
|
||||
.iter()
|
||||
.map(value_to_string)
|
||||
.collect::<Vec<_>>()
|
||||
.join(","),
|
||||
BencodeValue::Dict(map) => map
|
||||
.iter()
|
||||
.map(|(key, value)| format!("{key}={}", value_to_string(value)))
|
||||
.collect::<Vec<_>>()
|
||||
.join("&"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Hex-encodes raw torrent bytes using lowercase hexadecimal.
|
||||
pub(super) fn hex_encode(bytes: &[u8]) -> String {
|
||||
const HEX: &[u8; 16] = b"0123456789abcdef";
|
||||
let mut out = String::with_capacity(bytes.len() * 2);
|
||||
for &byte in bytes {
|
||||
out.push(char::from(HEX[usize::from(byte >> 4)]));
|
||||
out.push(char::from(HEX[usize::from(byte & 0x0f)]));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// Saturates an integer-like torrent length field into `u64`.
|
||||
pub(super) fn i64_to_u64(value: i64) -> u64 {
|
||||
u64::try_from(value.max(0)).unwrap_or(u64::MAX)
|
||||
}
|
||||
Reference in New Issue
Block a user