use crate::parse::{parse_bail, parse_uleb128_at, ParseAt, ParseErrorContext as _, ParseResult};
use crate::xo65::Xo65Bytes;
#[derive(Debug)]
pub struct MetadataTable<'data> {
bytes: Xo65Bytes<'data>,
metas: Box<[Metadata]>,
}
impl<'data> MetadataTable<'data> {
pub fn as_bytes(&self) -> &'data [u8] {
self.bytes.as_inner()
}
pub fn count(&self) -> usize {
self.metas.len()
}
pub fn get(&self, idx: usize) -> Option<&Metadata> {
self.metas.get(idx)
}
pub fn iter(
&self,
) -> impl DoubleEndedIterator<Item = &Metadata> + ExactSizeIterator + std::iter::FusedIterator + Clone
{
self.metas.iter()
}
pub(crate) fn parse(bytes: Xo65Bytes<'data>) -> ParseResult<Self> {
let mut off = 0;
let count = parse_uleb128_at(&bytes, &mut off)? as usize;
let mut metas = Vec::<Metadata>::with_capacity(count);
for i in 0..count {
let meta = Metadata::parse_at(&bytes, &mut off)
.with_context(|| format!("metadata {i} parse error"))?;
metas.push(meta);
}
Ok(Self {
bytes,
metas: metas.into(),
})
}
}
#[derive(Debug)]
pub enum Metadata {
Comment { str_idx: u32 },
Author { str_idx: u32 },
Translator { str_idx: u32 },
Compiler { str_idx: u32 },
Os { str_idx: u32 },
DateTime { unix_time: i32 },
}
impl ParseAt<'_> for Metadata {
fn parse_at(bytes: &Xo65Bytes<'_>, off: &mut usize) -> ParseResult<Self> {
let kind = u8::parse_at(bytes, off)?;
let value = parse_uleb128_at(bytes, off)?;
let meta = match kind {
0x00 => Self::Comment { str_idx: value },
0x01 => Self::Author { str_idx: value },
0x02 => Self::Translator { str_idx: value },
0x03 => Self::Compiler { str_idx: value },
0x04 => Self::Os { str_idx: value },
0x40 => Self::DateTime {
unix_time: value.cast_signed(),
},
_ => parse_bail!("unknown metadata kind: {kind:#X}"),
};
Ok(meta)
}
}