iso14229_1/request/
request_file_transfer.rs

1//! response of Service 38
2
3use crate::{ByteOrder, Configuration, error::Error, DataFormatIdentifier, ModeOfOperation, RequestData, utils};
4
5pub enum RequestFileTransfer {
6    AddFile {
7        filepath: String,
8        dfi: DataFormatIdentifier,
9        filesize_len: u8,
10        uncompressed_size: u128,
11        compressed_size: u128,
12    },
13    DeleteFile {    // 2
14        filepath: String,
15    },
16    ReplaceFile {   // 3
17        filepath: String,
18        dfi: DataFormatIdentifier,
19        filesize_len: u8,
20        uncompressed_size: u128,
21        compressed_size: u128,
22    },
23    ReadFile {       // 4
24        filepath: String,
25        dfi: DataFormatIdentifier,
26    },
27    ReadDir {       // 5
28        filepath: String,
29    },
30    ResumeFile {    // 6
31        filepath: String,
32        dfi: DataFormatIdentifier,
33        filesize_len: u8,
34        uncompressed_size: u128,
35        compressed_size: u128,
36    },
37}
38
39impl RequestData for RequestFileTransfer {
40    type SubFunc = ModeOfOperation;
41    fn try_parse(data: &[u8], sub_func: Option<Self::SubFunc>, _: &Configuration) -> Result<Self, Error> {
42        match sub_func {
43            Some(v) => {
44                let data_len = data.len();
45                utils::data_length_check(data_len, 3, false)?;
46                let mut offset = 0;
47
48                let len = u16::from_be_bytes([data[offset], data[offset + 1]]) as usize;
49                offset += 2;
50                utils::data_length_check(data_len, offset + len + 1, false)?;
51
52                let filepath = String::from_utf8(
53                    data[offset..offset + len].to_vec()
54                ).map_err(|_| Error::InvalidData(hex::encode(data)))?;
55                offset += len;
56
57                match v {
58                    ModeOfOperation::AddFile => {
59                        let dfi = DataFormatIdentifier::from(data[offset]);
60                        offset += 1;
61                        let filesize_len = data[offset];
62                        offset += 1;
63                        let uncompressed_size = utils::slice_to_u128(&data[offset..offset + filesize_len as usize], ByteOrder::Big);
64                        offset += filesize_len as usize;
65                        let compressed_size = utils::slice_to_u128(&data[offset..offset + filesize_len as usize], ByteOrder::Big);
66                        Ok(Self::AddFile { filepath, dfi, filesize_len, uncompressed_size, compressed_size })
67                    },
68                    ModeOfOperation::ReplaceFile => {
69                        let dfi = DataFormatIdentifier::from(data[offset]);
70                        offset += 1;
71                        let filesize_len = data[offset];
72                        offset += 1;
73                        let uncompressed_size = utils::slice_to_u128(&data[offset..offset + filesize_len as usize], ByteOrder::Big);
74                        offset += filesize_len as usize;
75                        let compressed_size = utils::slice_to_u128(&data[offset..offset + filesize_len as usize], ByteOrder::Big);
76                        Ok(Self::ReplaceFile { filepath, dfi, filesize_len, uncompressed_size, compressed_size })
77                    },
78                    ModeOfOperation::ResumeFile => {
79                        let dfi = DataFormatIdentifier::from(data[offset]);
80                        offset += 1;
81                        let filesize_len = data[offset];
82                        offset += 1;
83                        let uncompressed_size = utils::slice_to_u128(&data[offset..offset + filesize_len as usize], ByteOrder::Big);
84                        offset += filesize_len as usize;
85                        let compressed_size = utils::slice_to_u128(&data[offset..offset + filesize_len as usize], ByteOrder::Big);
86                        Ok(Self::ResumeFile { filepath, dfi, filesize_len, uncompressed_size, compressed_size })
87                    },
88                    ModeOfOperation::DeleteFile => Ok(Self::DeleteFile { filepath }),
89                    ModeOfOperation::ReadDir => Ok(Self::ReadDir { filepath }),
90                    ModeOfOperation::ReadFile => {
91                        let dfi = DataFormatIdentifier::from(data[offset]);
92
93                        Ok(Self::ReadFile {
94                            filepath,
95                            dfi
96                        })
97                    },
98                }
99            },
100            None => panic!("Sub-function required"),
101        }
102    }
103    #[inline]
104    fn to_vec(self, _: &Configuration) -> Vec<u8> {
105        self.into()
106    }
107}
108
109impl Into<Vec<u8>> for RequestFileTransfer {
110    fn into(self) -> Vec<u8> {
111        let mut result = Vec::new();
112        match &self {
113            Self::AddFile { .. } => result.push(ModeOfOperation::AddFile.into()),
114            Self::DeleteFile { .. } => result.push(ModeOfOperation::DeleteFile.into()),
115            Self::ReplaceFile { .. } => result.push(ModeOfOperation::ReplaceFile.into()),
116            Self::ReadFile { .. } => result.push(ModeOfOperation::ReadFile.into()),
117            Self::ReadDir { .. } => result.push(ModeOfOperation::ReadDir.into()),
118            Self::ResumeFile { .. } => result.push(ModeOfOperation::ResumeFile.into()),
119        }
120        match self {
121            Self::AddFile {
122                filepath,
123                dfi,
124                filesize_len,
125                uncompressed_size,
126                compressed_size,
127            } |
128            Self::ReplaceFile {
129                filepath,
130                dfi,
131                filesize_len,
132                uncompressed_size,
133                compressed_size,
134            } |
135            Self::ResumeFile {
136                filepath,
137                dfi,
138                filesize_len,
139                uncompressed_size,
140                compressed_size,
141            } => {
142                let mut bytes: Vec<_> = filepath.bytes().collect();
143                result.extend((bytes.len() as u16).to_be_bytes());
144                result.append(&mut bytes);
145                result.push(dfi.into());
146                result.push(filesize_len);
147
148                result.append(&mut utils::u128_to_vec(uncompressed_size, filesize_len as usize, ByteOrder::Big));
149                result.append(&mut utils::u128_to_vec(compressed_size, filesize_len as usize, ByteOrder::Big));
150            },
151            Self::DeleteFile { filepath, } |
152            Self::ReadDir { filepath, } => {
153                let mut bytes: Vec<_> = filepath.bytes().collect();
154                result.extend((bytes.len() as u16).to_be_bytes());
155                result.append(&mut bytes);
156            },
157            Self::ReadFile { filepath, dfi, } => {
158                let mut bytes: Vec<_> = filepath.bytes().collect();
159                result.extend((bytes.len() as u16).to_be_bytes());
160                result.append(&mut bytes);
161                result.push(dfi.into());
162            },
163        }
164
165        result
166    }
167}
168
169#[cfg(test)]
170mod tests {
171    use crate::{Configuration, DataFormatIdentifier, ModeOfOperation, RequestData};
172    use super::RequestFileTransfer;
173
174    #[test]
175    fn add_file() -> anyhow::Result<()> {
176        // D:\mapdata\europe\germany1.yxz
177        let source = hex::decode("3801001E443A5C6D6170646174615C6575726F70655C6765726D616E79312E79787A1102C3507530")?;
178
179        let cfg = Configuration::default();
180        let request = RequestFileTransfer::try_parse(&source[2..], Some(ModeOfOperation::AddFile), &cfg)?;
181        match request {
182            RequestFileTransfer::AddFile {
183                filepath,
184                dfi,
185                filesize_len,
186                uncompressed_size,
187                compressed_size,
188            } => {
189                assert_eq!(filepath, r"D:\mapdata\europe\germany1.yxz".to_string());
190                assert_eq!(dfi, DataFormatIdentifier(0x11));
191                assert_eq!(filesize_len, 0x02);
192                assert_eq!(uncompressed_size, 0xC350);
193                assert_eq!(compressed_size, 0x7530);
194            },
195            _ => panic!(),
196        }
197
198        Ok(())
199    }
200}