pub const CAP_BYTES: u64 = 1024 * 1024;
pub fn shell_quote(text: &str) -> String {
format!("'{}'", text.replace('\'', "'\\''"))
}
pub fn q_command(target: &str, query: &str) -> String {
format!("pdfboss q {} {}", shell_quote(target), shell_quote(query))
}
pub fn hex_command(target: &str, selector: &str) -> String {
format!(
"pdfboss hex {} {}",
shell_quote(target),
shell_quote(selector)
)
}
pub fn hexdump_text(bytes: &[u8], base: u64) -> String {
let lines: Vec<String> = bytes
.chunks(16)
.enumerate()
.map(|(index, chunk)| {
let mut hex = String::new();
for (position, byte) in chunk.iter().enumerate() {
if position > 0 {
hex.push(' ');
}
if position == 8 {
hex.push(' ');
}
hex.push_str(&format!("{byte:02x}"));
}
let ascii: String = chunk
.iter()
.map(|byte| {
if (0x20..=0x7e).contains(byte) {
char::from(*byte)
} else {
'.'
}
})
.collect();
let offset = base + (index as u64) * 16;
format!("{offset:08x}: {hex:<48} |{ascii}|")
})
.collect();
lines.join("\n")
}
pub fn human_size(len: u64) -> String {
if len < 1024 {
return format!("{len} B");
}
let kib = len as f64 / 1024.0;
if kib < 1024.0 {
return format!("{kib:.1} KiB");
}
format!("{:.1} MiB", kib / 1024.0)
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum YankTarget {
Query,
Command,
Hexdump,
Bytes,
Element,
Markdown,
ObjRef,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum YankFormat {
Hexdump,
Bytes,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn shell_quote_wraps_and_escapes_single_quotes() {
assert_eq!(shell_quote("plain.pdf"), "'plain.pdf'");
assert_eq!(shell_quote("o'clock.pdf"), "'o'\\''clock.pdf'");
}
#[test]
fn hex_command_quotes_target_and_selector() {
assert_eq!(
hex_command("my file.pdf", "range:0-16"),
"pdfboss hex 'my file.pdf' 'range:0-16'"
);
}
#[test]
fn hexdump_text_formats_sixteen_wide_from_the_base_offset() {
let mut bytes: Vec<u8> = (b'A'..=b'P').collect();
bytes.push(0x00);
bytes.push(b'Q');
assert_eq!(
hexdump_text(&bytes, 0xf),
"0000000f: 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 |ABCDEFGHIJKLMNOP|\n\
0000001f: 00 51 |.Q|"
);
}
#[test]
fn human_size_scales_units() {
assert_eq!(human_size(18), "18 B");
assert_eq!(human_size(4 * 1024), "4.0 KiB");
assert_eq!(human_size(3 * 1024 * 1024 / 2), "1.5 MiB");
}
}