use anyhow::{Context, Result};
use std::path::{Path, PathBuf};
pub struct RkyvStore {
pub path: PathBuf,
pub bytes: Vec<u8>,
}
pub struct StringHit {
pub offset: usize,
pub text: String,
}
impl RkyvStore {
pub fn open(path: &Path) -> Result<Self> {
let bytes = std::fs::read(path).with_context(|| format!("read {}", path.display()))?;
Ok(Self {
path: path.to_path_buf(),
bytes,
})
}
pub fn len(&self) -> usize {
self.bytes.len()
}
pub fn strings(&self, min_len: usize) -> Vec<StringHit> {
let mut hits = Vec::new();
let mut start: Option<usize> = None;
for (i, &b) in self.bytes.iter().enumerate() {
let printable = (0x20..0x7f).contains(&b);
match (printable, start) {
(true, None) => start = Some(i),
(false, Some(s)) => {
if i - s >= min_len {
hits.push(StringHit {
offset: s,
text: String::from_utf8_lossy(&self.bytes[s..i]).into_owned(),
});
}
start = None;
}
_ => {}
}
}
if let Some(s) = start {
if self.bytes.len() - s >= min_len {
hits.push(StringHit {
offset: s,
text: String::from_utf8_lossy(&self.bytes[s..]).into_owned(),
});
}
}
hits
}
pub fn hex_row(&self, offset: usize) -> String {
let end = (offset + 16).min(self.bytes.len());
let chunk = &self.bytes[offset.min(self.bytes.len())..end];
crate::hexedit::hex_dump_line(offset, chunk)
}
}