vst_audio_protocol/
state.rs1use 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}