use std::{collections::HashMap, fs::DirEntry, io::SeekFrom, path::Path, string::String};
use crate::{error::Error, section::SectionData, Interface, Result, SectionHandle};
use std::collections::hash_map::Entry;
pub struct StringSection
{
handle: SectionHandle,
cache: HashMap<u32, String>
}
impl StringSection
{
pub fn new(hdl: SectionHandle) -> StringSection
{
return StringSection {
handle: hdl,
cache: HashMap::new()
};
}
pub fn get<TInterface: Interface>(&mut self, interface: &mut TInterface, address: u32) -> Result<&str>
{
let res = match self.cache.entry(address) {
Entry::Occupied(o) => o.into_mut(),
Entry::Vacant(o) => {
let data = interface.open_section(self.handle)?;
let s = low_level_read_string(address, data)?;
o.insert(s)
}
};
return Ok(res);
}
pub fn put<TInterface: Interface>(&mut self, interface: &mut TInterface, s: &str) -> Result<u32>
{
let data = interface.open_section(self.handle)?;
let address = low_level_write_string(s, data)?;
self.cache.insert(address, String::from(s));
return Ok(address);
}
}
fn low_level_read_string(ptr: u32, string_section: &mut dyn SectionData) -> Result<String>
{
let mut curs: Vec<u8> = Vec::new();
let mut chr: [u8; 1] = [0; 1];
string_section.seek(SeekFrom::Start(ptr as u64))?;
string_section.read(&mut chr)?;
while chr[0] != 0x0 {
curs.push(chr[0]);
let res = string_section.read(&mut chr)?;
if res != 1 {
return Err(Error::Truncation("string secton read"));
}
}
return match String::from_utf8(curs) {
Err(_) => Err(Error::Utf8("string section read")),
Ok(v) => Ok(v)
}
}
fn low_level_write_string(s: &str, string_section: &mut dyn SectionData) -> Result<u32>
{
let ptr = string_section.size() as u32;
string_section.write(s.as_bytes())?;
string_section.write(&[0x0])?;
return Ok(ptr);
}
pub fn get_name_from_path(path: &Path) -> Result<String>
{
match path.file_name() {
Some(v) => match v.to_str() {
Some(v) => return Ok(String::from(v)),
None => panic!("Non unicode paths operating systems cannot run BPXP")
},
None => return Err(Error::from("incorrect path format"))
}
}
pub fn get_name_from_dir_entry(entry: &DirEntry) -> String
{
match entry.file_name().to_str() {
Some(v) => return String::from(v),
None => panic!("Non unicode paths operating systems cannot run BPXP")
}
}