pub mod qgd;
pub mod qtfl;
pub mod ttfl;
use std::io::Read;
use cfb::CompoundFile;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Variant {
Qgd,
Ttfl,
Qtfl,
}
const GCMS_ROOT: &str = "GCMS Raw Data";
const TTFL_ROOT: &str = "TTFL Raw Data";
const QTFL_ROOT: &str = "QTFL RawData";
pub fn detect_variant<F: Read + std::io::Seek>(
path_ext_lower: &str,
comp: &mut CompoundFile<F>,
) -> crate::Result<Variant> {
match path_ext_lower {
"qgd" => {
if comp.exists(GCMS_ROOT) {
Ok(Variant::Qgd)
} else {
Err(crate::Error::Parse(format!(
"'{GCMS_ROOT}' storage not found in .qgd file"
)))
}
}
"lcd" => {
if comp.exists(TTFL_ROOT) {
Ok(Variant::Ttfl)
} else if comp.exists(QTFL_ROOT) {
Ok(Variant::Qtfl)
} else {
Err(crate::Error::Parse(format!(
"neither '{TTFL_ROOT}' nor '{QTFL_ROOT}' storage found in .lcd file"
)))
}
}
other => Err(crate::Error::Parse(format!(
"unsupported file extension '.{other}' (expected .qgd or .lcd)"
))),
}
}
pub fn read_stream<F: Read + std::io::Seek>(
comp: &mut CompoundFile<F>,
path: &str,
) -> crate::Result<Vec<u8>> {
let mut stream = comp
.open_stream(path)
.map_err(|e| crate::Error::Parse(format!("stream '{path}' not found: {e}")))?;
let mut buf = Vec::new();
stream.read_to_end(&mut buf)?;
Ok(buf)
}
pub fn read_stream_opt<F: Read + std::io::Seek>(
comp: &mut CompoundFile<F>,
path: &str,
) -> Option<Vec<u8>> {
let mut stream = comp.open_stream(path).ok()?;
let mut buf = Vec::new();
stream.read_to_end(&mut buf).ok()?;
Some(buf)
}