pub(crate) const MAGIC: &[u8; 8] = b"HEPHPLOT";
pub(crate) const VERSION_MAJOR: u16 = 1;
#[cfg(feature = "document-write")]
pub(crate) const VERSION_MINOR: u16 = 0;
pub(crate) const CHUNK_HEAD: &[u8; 4] = b"HEAD";
pub(crate) const CHUNK_FONTS: &[u8; 4] = b"FONT";
pub(crate) const CHUNK_STRINGS: &[u8; 4] = b"STRS";
pub(crate) const CHUNK_GEOMETRY: &[u8; 4] = b"GEOM";
pub(crate) const CHUNK_SHEETS: &[u8; 4] = b"SHET";
pub(crate) const CHUNK_THEME: &[u8; 4] = b"THEM";
pub(crate) const CHUNK_SCALES: &[u8; 4] = b"SCAL";
pub(crate) const CHUNK_COMPOSITION: &[u8; 4] = b"COMP";
pub(crate) const CHUNK_PLOTS: &[u8; 4] = b"PLOT";
#[cfg(feature = "document-read")]
#[derive(Debug)]
pub(crate) struct Chunk<'a> {
pub(crate) tag: [u8; 4],
pub(crate) body: &'a [u8],
}
#[cfg(feature = "document-read")]
pub(crate) fn parse(bytes: &[u8]) -> Result<Vec<Chunk<'_>>, super::DocumentError> {
use super::codec::Reader;
use super::DocumentError;
let mut r = Reader::new(bytes);
if r.take(MAGIC.len()).ok() != Some(&MAGIC[..]) {
return Err(DocumentError::BadMagic);
}
let major = r.u16_fixed()?;
let _minor = r.u16_fixed()?;
if major != VERSION_MAJOR {
return Err(DocumentError::UnsupportedVersion {
found: major,
supported: VERSION_MAJOR,
});
}
let mut out = Vec::new();
while !r.is_empty() {
let tag = r.take(4)?;
let tag = [tag[0], tag[1], tag[2], tag[3]];
let len = r.u32_fixed()? as usize;
out.push(Chunk {
tag,
body: r.take(len)?,
});
}
Ok(out)
}
#[cfg(feature = "document-read")]
pub(crate) fn chunk<'a>(chunks: &[Chunk<'a>], tag: &[u8; 4]) -> Option<&'a [u8]> {
chunks.iter().find(|c| &c.tag == tag).map(|c| c.body)
}
#[cfg(feature = "document-write")]
pub(crate) fn assemble(w: &mut super::codec::Writer, chunks: &[(&[u8; 4], Vec<u8>)]) {
w.raw(MAGIC);
w.u16_fixed(VERSION_MAJOR);
w.u16_fixed(VERSION_MINOR);
for (tag, body) in chunks {
w.raw(*tag);
let length_at = w.len();
w.u32_fixed(0);
w.raw(body);
let written = (w.len() - length_at - 4) as u32;
w.patch_u32_at(length_at, written);
}
}