osdp/command/
file_transfer.rs1use crate::error::Error;
6use crate::payload_util::require_at_least;
7use alloc::vec::Vec;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct FileTransfer {
12 pub file_type: u8,
14 pub total_size: u32,
16 pub offset: u32,
18 pub fragment: Vec<u8>,
20}
21
22impl FileTransfer {
23 pub fn encode(&self) -> Result<Vec<u8>, Error> {
25 if self.fragment.len() > u16::MAX as usize {
26 return Err(Error::MalformedPayload {
27 code: 0x7C,
28 reason: "FILETRANSFER fragment > 65535 bytes",
29 });
30 }
31 let mut out = Vec::with_capacity(11 + self.fragment.len());
32 out.push(self.file_type);
33 out.extend_from_slice(&self.total_size.to_le_bytes());
34 out.extend_from_slice(&self.offset.to_le_bytes());
35 out.extend_from_slice(&(self.fragment.len() as u16).to_le_bytes());
36 out.extend_from_slice(&self.fragment);
37 Ok(out)
38 }
39
40 pub fn decode(data: &[u8]) -> Result<Self, Error> {
42 require_at_least(data, 11, 0x7C)?;
43 let total_size = u32::from_le_bytes([data[1], data[2], data[3], data[4]]);
44 let offset = u32::from_le_bytes([data[5], data[6], data[7], data[8]]);
45 let frag_len = u16::from_le_bytes([data[9], data[10]]) as usize;
46 if data.len() != 11 + frag_len {
47 return Err(Error::MalformedPayload {
48 code: 0x7C,
49 reason: "FILETRANSFER fragment length disagrees with payload",
50 });
51 }
52 Ok(Self {
53 file_type: data[0],
54 total_size,
55 offset,
56 fragment: data[11..11 + frag_len].to_vec(),
57 })
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn roundtrip() {
67 let body = FileTransfer {
68 file_type: 0x07,
69 total_size: 0x0000_0100,
70 offset: 0x0000_0040,
71 fragment: alloc::vec![0xAA, 0xBB, 0xCC],
72 };
73 let bytes = body.encode().unwrap();
74 assert_eq!(
76 bytes,
77 [
78 0x07, 0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x03, 0x00, 0xAA, 0xBB, 0xCC
79 ]
80 );
81 assert_eq!(FileTransfer::decode(&bytes).unwrap(), body);
82 }
83
84 #[test]
85 fn decode_rejects_short_header() {
86 assert!(matches!(
87 FileTransfer::decode(&[0; 10]),
88 Err(Error::PayloadTooShort { code: 0x7C, .. })
89 ));
90 }
91
92 #[test]
93 fn decode_rejects_length_mismatch() {
94 let bad = [
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0xAA, 0xBB,
97 ];
98 assert!(matches!(
99 FileTransfer::decode(&bad),
100 Err(Error::MalformedPayload { code: 0x7C, .. })
101 ));
102 }
103}