Skip to main content

vst_audio_protocol/
state.rs

1//! Versioned VST 3 state envelope. VST 2 chunks retain their native representation.
2use crate::PluginError;
3const MAGIC: &[u8; 5] = b"SSV3\x01";
4const LIMIT: usize = crate::MAX_STATE_BODY_BYTES;
5
6pub fn encode(component: &[u8], controller: &[u8]) -> Result<Vec<u8>, PluginError> {
7    if component
8        .len()
9        .saturating_add(controller.len())
10        .saturating_add(13)
11        > LIMIT
12    {
13        return Err(PluginError("VST 3 state too large".into()));
14    }
15    let mut blob = Vec::with_capacity(13 + component.len() + controller.len());
16    blob.extend_from_slice(MAGIC);
17    for bytes in [component, controller] {
18        blob.extend_from_slice(&(bytes.len() as u32).to_le_bytes());
19        blob.extend_from_slice(bytes);
20    }
21    Ok(blob)
22}
23
24pub fn decode(blob: &[u8]) -> Result<(&[u8], &[u8]), PluginError> {
25    let invalid = || PluginError("invalid VST 3 state magic, version or framing".into());
26    if blob.len() > LIMIT || !blob.starts_with(MAGIC) {
27        return Err(invalid());
28    }
29    let mut rest = &blob[MAGIC.len()..];
30    fn part<'a>(rest: &mut &'a [u8]) -> Option<&'a [u8]> {
31        let length = u32::from_le_bytes(rest.get(..4)?.try_into().ok()?) as usize;
32        *rest = &rest[4..];
33        let bytes = rest.get(..length)?;
34        *rest = &rest[length..];
35        Some(bytes)
36    }
37    let component = part(&mut rest).ok_or_else(invalid)?;
38    let controller = part(&mut rest).ok_or_else(invalid)?;
39    if !rest.is_empty() {
40        return Err(invalid());
41    }
42    Ok((component, controller))
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48    #[test]
49    fn vst3_state_framing_round_trip() {
50        let blob = encode(&[1, 3], &[4, 5, 6]).unwrap();
51        assert_eq!(decode(&blob).unwrap(), (&[1, 3][..], &[4, 5, 6][..]));
52        for length in 0..blob.len() {
53            assert!(decode(&blob[..length]).is_err());
54        }
55        assert!(decode(&[1, 3]).is_err());
56        let mut corrupt = blob.clone();
57        corrupt[4] = 2;
58        assert!(decode(&corrupt).is_err());
59        corrupt = blob.clone();
60        corrupt.extend_from_slice(&[0]);
61        assert!(decode(&corrupt).is_err());
62        assert_eq!(
63            decode(&encode(&[], &[]).unwrap()).unwrap(),
64            (&[][..], &[][..])
65        );
66    }
67}