slpm_file/
header_binary_v0.rs1use std::convert::TryFrom;
2
3use pad::PadStr;
4
5use crate::datatype::DataType;
6use crate::header_v0::HeaderV0;
7
8const MAGIC_NUMBER_SIZE: usize = 10;
10const MAGIC_NUMBER: [u8; MAGIC_NUMBER_SIZE] = *b"slpm-filef";
11const VERSION: u16 = 0;
12
13const HEADER_SIZE: usize = 1024;
14
15const VERSION_SIZE: usize = 2;
16const DATATYPE_SIZE: usize = 1;
17const NAME_SIZE: usize = 128;
18const CREATED_SIZE: usize = 8;
19const EDITED_SIZE: usize = 8;
20const FILE_NAME_SIZE: usize = 128;
21const BUFFER_SIZE_SIZE: usize = 8;
22
23#[derive(Clone, Hash, Debug, Eq, Ord, PartialOrd, PartialEq)]
25pub struct HeaderBinaryV0 {
26 pub magic_number: [u8; MAGIC_NUMBER_SIZE],
28
29 pub version: [u8; VERSION_SIZE],
31
32 pub datatype: [u8; DATATYPE_SIZE],
34
35 pub name: [u8; NAME_SIZE],
37
38 pub created: [u8; CREATED_SIZE],
40
41 pub edited: [u8; EDITED_SIZE],
43
44 pub file_name: [u8; FILE_NAME_SIZE],
46
47 pub buffer_size: [u8; BUFFER_SIZE_SIZE],
49
50}
51
52impl HeaderBinaryV0 {
53 #[must_use]
54 pub fn to_bytes(&self) -> Vec<u8> {
55
56 let mut output = Vec::new();
58 output.extend_from_slice(&self.magic_number);
59 output.extend_from_slice(&self.version);
60 output.extend_from_slice(&self.datatype);
61 output.extend_from_slice(&self.name);
62 output.extend_from_slice(&self.created);
63 output.extend_from_slice(&self.edited);
64 output.extend_from_slice(&self.file_name);
65 output.extend_from_slice(&self.buffer_size);
66 output.resize(HEADER_SIZE, 0);
67 output
68 }
69
70 #[must_use]
74 pub fn from_bytes(bytes: &[u8; HEADER_SIZE]) -> Self {
75 let mut position = 0_usize;
76
77 let magic_number = <[u8; MAGIC_NUMBER_SIZE]>::try_from(&bytes[position..position + MAGIC_NUMBER_SIZE]).unwrap();
78 position += MAGIC_NUMBER_SIZE;
79
80 let version = <[u8; VERSION_SIZE]>::try_from(&bytes[position..position + VERSION_SIZE]).unwrap();
81 position += VERSION_SIZE;
82
83 #[allow(clippy::range_plus_one)] let datatype = <[u8; DATATYPE_SIZE]>::try_from(&bytes[position..position + DATATYPE_SIZE]).unwrap();
85 position += DATATYPE_SIZE;
86
87 let name = <[u8; NAME_SIZE]>::try_from(&bytes[position..position + NAME_SIZE]).unwrap();
88 position += NAME_SIZE;
89
90 let created = <[u8; CREATED_SIZE]>::try_from(&bytes[position..position + CREATED_SIZE]).unwrap();
91 position += CREATED_SIZE;
92
93 let edited = <[u8; EDITED_SIZE]>::try_from(&bytes[position..position + EDITED_SIZE]).unwrap();
94 position += EDITED_SIZE;
95
96 let file_name = <[u8; FILE_NAME_SIZE]>::try_from(&bytes[position..position + FILE_NAME_SIZE]).unwrap();
97 position += FILE_NAME_SIZE;
98
99 let buffer_size = <[u8; BUFFER_SIZE_SIZE]>::try_from(&bytes[position..position + BUFFER_SIZE_SIZE]).unwrap();
100 Self {
103 magic_number,
104 version,
105 datatype,
106 name,
107 created,
108 edited,
109 file_name,
110 buffer_size,
111 }
112 }
113 #[must_use]
117 pub fn from_parameters(datatype: &DataType, name: &str, old_create_date: Option<i64>, file_name: &str, buffer_size: u64) -> Self {
118 let mut create_date = chrono::Local::now().timestamp();
119 if let Some(create) = old_create_date {
120 create_date = create;
121 }
122
123 let datatype_id: u8;
124 match datatype {
125 DataType::Password => { datatype_id = 0 }
126 DataType::File => { datatype_id = 1 }
127 }
128
129 let name_padded = name.pad_to_width(NAME_SIZE);
130 let file_name_padded = file_name.pad_to_width(FILE_NAME_SIZE);
131
132 Self {
133 magic_number: MAGIC_NUMBER,
134 version: VERSION.to_be_bytes(), datatype: datatype_id.to_be_bytes(),
136 name: <[u8; NAME_SIZE]>::try_from(name_padded.as_bytes()).unwrap(),
137 created: create_date.to_be_bytes(),
138 edited: chrono::Local::now().timestamp().to_be_bytes(),
139 file_name: <[u8; NAME_SIZE]>::try_from(file_name_padded.as_bytes()).unwrap(),
140 buffer_size: buffer_size.to_be_bytes(),
141 }
142 }
143 #[must_use]
147 pub fn from_header(header: &HeaderV0) -> Self {
148 let data_type: u8;
149 match header.datatype {
150 DataType::Password => data_type = 0,
151 DataType::File => data_type = 1
152 }
153 Self {
154 magic_number: MAGIC_NUMBER,
155 version: header.version.to_be_bytes(), datatype: data_type.to_be_bytes(),
157 name: <[u8; NAME_SIZE]>::try_from(header.name.as_bytes()).unwrap(),
158 created: header.created.to_be_bytes(),
159 edited: header.edited.to_be_bytes(),
160 file_name: <[u8; FILE_NAME_SIZE]>::try_from(header.file_name.as_bytes()).unwrap(),
161 buffer_size: header.buffer_size.to_be_bytes(),
162 }
163 }
164
165 #[must_use]pub fn to_header(&self) -> HeaderV0 {
169 let datatype: DataType;
170 match u8::from_be_bytes(self.datatype) {
171 0 => datatype = DataType::Password,
172 1 => datatype = DataType::File,
173 _ => {panic!("cannot match datatype")}
174 }
175
176 HeaderV0 {
177 version: VERSION,
178 datatype,
179 name: String::from_utf8(Vec::from(self.name)).unwrap(),
180 created: u64::from_be_bytes(self.created),
181 edited: u64::from_be_bytes(self.created),
182 file_name: String::from_utf8(Vec::from(self.file_name)).unwrap(),
183 buffer_size: u64::from_be_bytes(self.buffer_size)
184 }
185 }
186}