#![deny(warnings, rust_2018_idioms)]
/// Implementation of `character-string`s as defined by RFC1035 section 3.3
use anyhow::{bail, Result};
use bytes::{BufMut, Bytes, BytesMut};
/// Writes a `character-string`: A length byte followed by a 0-255 byte payload.
/// Returns an error if the provided `in_buf` exceeds 255 bytes.
pub fn write(in_buf: &[u8], out_buf: &mut BytesMut, description: &str) -> Result<()> {
if in_buf.len() > 255 {
bail!(
"{} length {} exceeds maximum 255",
description,
in_buf.len()
);
}
out_buf.reserve(1 + in_buf.len());
out_buf.put_u8(in_buf.len() as u8);
out_buf.put_slice(&in_buf);
return Ok(());
}
/// Reads a `character-string`: A length byte followed by a 0-255 byte payload, from the specified offset in `in_buf`.
/// This is different from `domain-name`s where each label is 0-63 bytes, and a "length" exceeding 192 indicates a pointer.
/// Returns an error if `in_buf`+`original_offset` doesn't have enough room for the length byte or the payload
pub fn read(in_buf: &[u8], original_offset: usize, description: &str) -> Result<(usize, Bytes)> {
let mut offset = original_offset;
let mut out = BytesMut::new();
// First byte should be size of label (0-255)
if in_buf.len() < offset + 1 {
bail!("{} is empty, expected string size", description);
}
let label_size = in_buf[offset] as usize;
offset += 1;
// Fetch remaining bytes and include trailing '.'
if in_buf.len() < offset + label_size {
bail!(
"{} remaining buffer length {} is shorter than required offset {} + string {}",
description,
in_buf.len(),
offset,
label_size
);
}
out.extend_from_slice(&in_buf[offset..offset + label_size]);
return Ok((1 + label_size, out.freeze()));
}