use std::io::{Read, Write};
use {Error, Header, SectionContent};
#[derive(Debug, Default, Clone)]
pub struct Strtab {
data: Vec<u8>,
}
impl Strtab {
pub fn len(&self, _: &Header) -> usize {
self.data.len()
}
pub fn entsize(_: &Header) -> usize {
1
}
pub fn from_reader(
mut io: impl Read,
_: Option<&SectionContent>,
_: &Header,
) -> Result<SectionContent, Error> {
let mut data = Vec::new();
io.read_to_end(&mut data)?;
Ok(SectionContent::Strtab(Strtab { data }))
}
pub fn to_writer(&self, mut io: impl Write, _: &Header) -> Result<usize, Error> {
Ok(io.write(&self.data)?)
}
pub fn get(&self, i: usize) -> Vec<u8> {
if i >= self.data.len() {
println!("pointer {} into strtab extends beyond section size", i);
return b"<corrupt>".to_vec();
}
self.data[i..]
.split(|&c| c == 0)
.next()
.unwrap_or(&[0; 0])
.to_vec()
}
pub fn insert(&mut self, ns: &[u8]) -> usize {
if let Some(max_start) = self.data.len().checked_sub(ns.len() + 1) {
for start in 0..=max_start {
if self.data[start..].starts_with(ns) {
if self.data[start + ns.len()] == 0 {
return start;
}
}
}
}
let i = self.data.len();
self.data.extend(ns);
self.data.push(0);
i
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_insert_then_get() {
let ns1: &[u8] = b".text";
let ns2: &[u8] = b".data";
let mut strtab = Strtab { data: Vec::new() };
assert_eq!(strtab.insert(&[]), 0);
assert_eq!(strtab.insert(ns1), 1);
assert_eq!(strtab.insert(ns2), 2 + ns1.len());
assert_eq!(strtab.get(0), &[]);
assert_eq!(strtab.get(1), ns1);
assert_eq!(strtab.get(2 + ns1.len()), ns2);
}
#[test]
fn test_insert_suffix() {
let mut strtab = Strtab { data: Vec::new() };
assert_eq!(strtab.insert(b".text"), 0);
let old_size = strtab.data.len();
assert_eq!(strtab.insert(b"xt"), 3);
assert_eq!(strtab.data.len(), old_size);
}
#[test]
fn test_starting_data() {
let ns = b".text";
let mut data = vec![0];
data.extend(ns);
data.push(0);
let mut strtab = Strtab { data };
assert_eq!(strtab.get(1), ns);
assert_eq!(strtab.insert(b".data"), 2 + ns.len());
}
#[test]
fn test_only_data() {
let ns: &[u8] = b".text";
let mut data = vec![];
data.extend(ns);
data.push(0);
let mut strtab = Strtab { data };
assert_eq!(strtab.get(0), ns);
assert_eq!(strtab.insert(ns), 0);
assert_eq!(strtab.get(0), ns);
}
#[test]
fn test_insert_prefix() {
let mut data = vec![];
data.extend(b".text");
data.push(0);
let mut strtab = Strtab { data };
assert_eq!(strtab.insert(b".tex"), 6);
}
}