From 3f90e84c5bb4d3dfc98290d3f689efd5843238cf Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Fri, 5 Jan 2024 17:36:43 +0100 Subject: [PATCH] xmpp-parsers: Add a hexadecimal codec That one accepts both uppercase and lowercase hexadecimal input, and outputs in lowercase. It requires no separator between bytes, unlike ColonSeparatedHex. --- parsers/src/util/helpers.rs | 48 +++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/parsers/src/util/helpers.rs b/parsers/src/util/helpers.rs index ff30993..752dcfe 100644 --- a/parsers/src/util/helpers.rs +++ b/parsers/src/util/helpers.rs @@ -84,6 +84,27 @@ impl WhitespaceAwareBase64 { } } +/// Codec for bytes of lowercase hexadecimal. +pub struct Hex; + +impl Hex { + pub fn decode(s: &str) -> Result, Error> { + let mut bytes = Vec::with_capacity(s.len() / 2); + for i in 0..s.len() / 2 { + bytes.push(u8::from_str_radix(&s[2 * i..2 * i + 2], 16)?); + } + Ok(bytes) + } + + pub fn encode(b: &[u8]) -> Option { + let mut bytes = String::with_capacity(b.len() * 2); + for byte in b { + bytes.extend(format!("{:02x}", byte).chars()); + } + Some(bytes) + } +} + /// Codec for colon-separated bytes of uppercase hexadecimal. pub struct ColonSeparatedHex; @@ -121,3 +142,30 @@ impl JidCodec { Some(jid.to_string()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn hex() { + let value = [0x01, 0xfe, 0xef]; + + // Test that we support both lowercase and uppercase as input. + let hex = Hex::decode("01feEF").unwrap(); + assert_eq!(hex, &value); + + // Test that we do output lowercase. + let hex = Hex::encode(&value).unwrap(); + assert_eq!(hex, "01feef"); + } + + #[test] + fn bad_hex() { + // No colon supported. + Hex::decode("01:fe:EF").unwrap_err(); + + // No non-hex character allowed. + Hex::decode("01defg").unwrap_err(); + } +}