use crate::*;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct KeyEntry {
pub key_namespace: FourCC,
pub key_value: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Keys {
pub entries: Vec<KeyEntry>,
}
impl AtomExt for Keys {
type Ext = ();
const KIND_EXT: FourCC = FourCC::new(b"keys");
fn decode_body_ext<B: Buf>(buf: &mut B, _ext: ()) -> Result<Self> {
let entry_count = u32::decode(buf)?;
let mut entries = Vec::with_capacity((entry_count as usize).min(4096));
for _ in 0..entry_count {
let header = Header::decode(buf)?;
let size = header.size.ok_or(Error::InvalidSize)?;
if size > buf.remaining() {
return Err(Error::OutOfBounds);
}
let key_value = String::from_utf8(buf.slice(size).to_vec())
.map_err(|err| Error::InvalidString(err.to_string()))?;
buf.advance(size);
entries.push(KeyEntry {
key_namespace: header.kind,
key_value,
});
}
Ok(Self { entries })
}
fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<()> {
(self.entries.len() as u32).encode(buf)?;
for entry in &self.entries {
let header = Header {
kind: entry.key_namespace,
size: Some(entry.key_value.len()),
};
header.encode(buf)?;
entry.key_value.as_bytes().encode(buf)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_keys_roundtrip() {
let keys = Keys {
entries: vec![
KeyEntry {
key_namespace: FourCC::new(b"mdta"),
key_value: "com.apple.quicktime.make".into(),
},
KeyEntry {
key_namespace: FourCC::new(b"mdta"),
key_value: "com.apple.quicktime.model".into(),
},
],
};
let mut buf = Vec::new();
keys.encode(&mut buf).unwrap();
let decoded = Keys::decode(&mut buf.as_slice()).expect("failed to decode keys");
assert_eq!(decoded, keys);
}
#[test]
fn test_keys_truncated_entry_does_not_panic() {
let mut buf = Vec::new();
buf.extend_from_slice(&24u32.to_be_bytes()); buf.extend_from_slice(b"keys");
buf.extend_from_slice(&0u32.to_be_bytes()); buf.extend_from_slice(&1u32.to_be_bytes());
buf.extend_from_slice(&108u32.to_be_bytes());
buf.extend_from_slice(b"mdta");
let result = Keys::decode(&mut buf.as_slice());
assert!(result.is_err());
}
#[test]
fn test_keys_empty() {
let keys = Keys::default();
let mut buf = Vec::new();
keys.encode(&mut buf).unwrap();
let decoded = Keys::decode(&mut buf.as_slice()).expect("failed to decode keys");
assert_eq!(decoded, keys);
}
#[test]
fn test_keys_truncated_entry() {
let mut buf = Vec::new();
0u32.encode(&mut buf).unwrap(); 1u32.encode(&mut buf).unwrap(); 100u32.encode(&mut buf).unwrap(); FourCC::new(b"mdta").encode(&mut buf).unwrap();
buf.extend_from_slice(b"short");
let err = Keys::decode_body(&mut buf.as_slice()).unwrap_err();
assert!(matches!(err, Error::OutOfBounds));
}
#[test]
fn test_keys_malformed_count() {
let mut buf = Vec::new();
0u32.encode(&mut buf).unwrap(); u32::MAX.encode(&mut buf).unwrap(); FourCC::new(b"mdta").encode(&mut buf).unwrap();
let err = Keys::decode_body(&mut buf.as_slice()).unwrap_err();
assert!(matches!(err, Error::OutOfBounds));
}
}