1use std::io::{Cursor, Read};
3use std::collections::HashMap;
4
5use crate::{
7 Result,
8 HeaderCoding,
9 ValueDecoder,
10 ValueEncoder,
11 ZffError,
12 ZffErrorKind,
13 FOOTER_IDENTIFIER_OBJECT_FOOTER_PHYSICAL,
14 FOOTER_IDENTIFIER_OBJECT_FOOTER_LOGICAL,
15 DEFAULT_LENGTH_VALUE_HEADER_LENGTH,
16 DEFAULT_LENGTH_HEADER_IDENTIFIER,
17 ERROR_HEADER_DECODER_MISMATCH_IDENTIFIER,
18 ERROR_HEADER_DECODER_HEADER_LENGTH,
19};
20use crate::header::{
21 HashHeader,
22};
23
24use byteorder::{LittleEndian, BigEndian, ReadBytesExt};
26
27#[derive(Debug, Clone)]
29pub enum ObjectFooter {
30 Physical(ObjectFooterPhysical),
32 Logical(ObjectFooterLogical),
34}
35
36impl ObjectFooter {
37 pub fn version(&self) -> u8 {
39 match self {
40 ObjectFooter::Physical(phy) => phy.version(),
41 ObjectFooter::Logical(log) => log.version(),
42 }
43 }
44
45 fn check_identifier<R: Read>(data: &mut R) -> u8 {
47 let identifier = match data.read_u32::<BigEndian>() {
48 Ok(val) => val,
49 Err(_) => return 0,
50 };
51 if identifier == ObjectFooterPhysical::identifier() {
52 1
53 } else if identifier == ObjectFooterLogical::identifier() {
54 2
55 } else {
56 0
57 }
58 }
59
60 fn decode_header_length<R: Read>(data: &mut R) -> Result<u64> {
62 match data.read_u64::<LittleEndian>() {
63 Ok(value) => Ok(value),
64 Err(_) => Err(ZffError::new_header_decode_error(ERROR_HEADER_DECODER_HEADER_LENGTH)),
65 }
66 }
67
68 pub fn decode_directly<R: Read>(data: &mut R) -> Result<ObjectFooter> {
71 match Self::check_identifier(data) {
72 1 => {
73 let length = Self::decode_header_length(data)? as usize;
74 let mut content_buffer = vec![0u8; length-DEFAULT_LENGTH_HEADER_IDENTIFIER-DEFAULT_LENGTH_VALUE_HEADER_LENGTH];
75 data.read_exact(&mut content_buffer)?;
76 Ok(ObjectFooter::Physical(ObjectFooterPhysical::decode_content(content_buffer)?))
77 },
78 2 => {
79 let length = Self::decode_header_length(data)? as usize;
80 let mut content_buffer = vec![0u8; length-DEFAULT_LENGTH_HEADER_IDENTIFIER-DEFAULT_LENGTH_VALUE_HEADER_LENGTH];
81 data.read_exact(&mut content_buffer)?;
82 Ok(ObjectFooter::Logical(ObjectFooterLogical::decode_content(content_buffer)?))
83 },
84 _ => Err(ZffError::new(ZffErrorKind::HeaderDecodeMismatchIdentifier, ERROR_HEADER_DECODER_MISMATCH_IDENTIFIER)),
85 }
86 }
87}
88
89#[derive(Debug,Clone)]
98pub struct ObjectFooterPhysical {
99 version: u8,
100 acquisition_start: u64,
101 acquisition_end: u64,
102 length_of_data: u64,
103 first_chunk_number: u64,
104 number_of_chunks: u64,
105 hash_header: HashHeader,
106}
107
108impl ObjectFooterPhysical {
109 pub fn new(version: u8, acquisition_start: u64, acquisition_end: u64, length_of_data: u64, first_chunk_number: u64, number_of_chunks: u64, hash_header: HashHeader) -> ObjectFooterPhysical {
111 Self {
112 version,
113 acquisition_start,
114 acquisition_end,
115 length_of_data,
116 first_chunk_number,
117 number_of_chunks,
118 hash_header,
119 }
120 }
121
122 pub fn acquisition_start(&self) -> u64 {
124 self.acquisition_start
125 }
126
127 pub fn acquisition_end(&self) -> u64 {
129 self.acquisition_end
130 }
131
132 pub fn first_chunk_number(&self) -> u64 {
134 self.first_chunk_number
135 }
136
137 pub fn number_of_chunks(&self) -> u64 {
139 self.number_of_chunks
140 }
141
142 pub fn length_of_data(&self) -> u64 {
144 self.length_of_data
145 }
146
147 pub fn hash_header(&self) -> &HashHeader {
149 &self.hash_header
150 }
151}
152
153impl HeaderCoding for ObjectFooterPhysical {
154 type Item = ObjectFooterPhysical;
155 fn version(&self) -> u8 {
156 self.version
157 }
158 fn identifier() -> u32 {
159 FOOTER_IDENTIFIER_OBJECT_FOOTER_PHYSICAL
160 }
161 fn encode_header(&self) -> Vec<u8> {
162 let mut vec = vec![self.version];
163 vec.append(&mut self.acquisition_start.encode_directly());
164 vec.append(&mut self.acquisition_end.encode_directly());
165 vec.append(&mut self.length_of_data.encode_directly());
166 vec.append(&mut self.first_chunk_number.encode_directly());
167 vec.append(&mut self.number_of_chunks.encode_directly());
168 vec.append(&mut self.hash_header.encode_directly());
169 vec
170 }
171 fn decode_content(data: Vec<u8>) -> Result<ObjectFooterPhysical> {
172 let mut cursor = Cursor::new(data);
173 let footer_version = u8::decode_directly(&mut cursor)?;
174 let acquisition_start = u64::decode_directly(&mut cursor)?;
175 let acquisition_end = u64::decode_directly(&mut cursor)?;
176 let length_of_data = u64::decode_directly(&mut cursor)?;
177 let first_chunk_number = u64::decode_directly(&mut cursor)?;
178 let number_of_chunks = u64::decode_directly(&mut cursor)?;
179 let hash_header = HashHeader::decode_directly(&mut cursor)?;
180 Ok(ObjectFooterPhysical::new(footer_version, acquisition_start, acquisition_end, length_of_data, first_chunk_number, number_of_chunks, hash_header))
181 }
182}
183
184#[derive(Debug,Clone)]
194pub struct ObjectFooterLogical {
195 version: u8,
196 acquisition_start: u64,
197 acquisition_end: u64,
198 root_dir_filenumbers: Vec<u64>,
199 file_header_segment_numbers: HashMap<u64, u64>,
200 file_header_offsets: HashMap<u64, u64>,
201 file_footer_segment_numbers: HashMap<u64, u64>,
202 file_footer_offsets: HashMap<u64, u64>,
203}
204
205impl ObjectFooterLogical {
206 pub fn new_empty(version: u8) -> ObjectFooterLogical {
208 Self {
209 version,
210 acquisition_start: 0,
211 acquisition_end: 0,
212 root_dir_filenumbers: Vec::new(),
213 file_header_segment_numbers: HashMap::new(),
214 file_header_offsets: HashMap::new(),
215 file_footer_segment_numbers: HashMap::new(),
216 file_footer_offsets: HashMap::new()
217 }
218 }
219
220 #[allow(clippy::too_many_arguments)]
222 pub fn new(
223 version: u8,
224 acquisition_start: u64,
225 acquisition_end: u64,
226 root_dir_filenumbers: Vec<u64>,
227 file_header_segment_numbers: HashMap<u64, u64>,
228 file_header_offsets: HashMap<u64, u64>,
229 file_footer_segment_numbers: HashMap<u64, u64>,
230 file_footer_offsets: HashMap<u64, u64>) -> ObjectFooterLogical {
231 Self {
232 version,
233 acquisition_start,
234 acquisition_end,
235 root_dir_filenumbers,
236 file_header_segment_numbers,
237 file_header_offsets,
238 file_footer_segment_numbers,
239 file_footer_offsets,
240 }
241 }
242
243 pub fn add_root_dir_filenumber(&mut self, filenumber: u64) {
245 self.root_dir_filenumbers.push(filenumber)
246 }
247
248 pub fn root_dir_filenumbers(&self) -> &Vec<u64> {
250 &self.root_dir_filenumbers
251 }
252
253 pub fn add_file_header_segment_number(&mut self, filenumber: u64, file_segment_number: u64) {
256 self.file_header_segment_numbers.insert(filenumber, file_segment_number);
257 }
258
259 pub fn add_file_header_offset(&mut self, filenumber: u64, fileoffset: u64) {
262 self.file_header_offsets.insert(filenumber, fileoffset);
263 }
264
265 pub fn file_header_segment_numbers(&self) -> &HashMap<u64, u64> {
267 &self.file_header_segment_numbers
268 }
269
270 pub fn file_header_offsets(&self) -> &HashMap<u64, u64> {
272 &self.file_header_offsets
273 }
274
275 pub fn add_file_footer_segment_number(&mut self, filenumber: u64, file_segment_number: u64) {
278 self.file_footer_segment_numbers.insert(filenumber, file_segment_number);
279 }
280
281 pub fn add_file_footer_offset(&mut self, filenumber: u64, fileoffset: u64) {
284 self.file_footer_offsets.insert(filenumber, fileoffset);
285 }
286
287 pub fn file_footer_segment_numbers(&self) -> &HashMap<u64, u64> {
289 &self.file_footer_segment_numbers
290 }
291
292 pub fn file_footer_offsets(&self) -> &HashMap<u64, u64> {
294 &self.file_footer_offsets
295 }
296
297 pub fn acquisition_start(&self) -> u64 {
299 self.acquisition_start
300 }
301
302 pub fn acquisition_end(&self) -> u64 {
304 self.acquisition_end
305 }
306
307 pub fn set_acquisition_start(&mut self, start: u64) {
309 self.acquisition_start = start;
310 }
311
312 pub fn set_acquisition_end(&mut self, end: u64) {
314 self.acquisition_end = end;
315 }
316}
317
318impl HeaderCoding for ObjectFooterLogical {
319 type Item = ObjectFooterLogical;
320
321 fn version(&self) -> u8 {
322 self.version
323 }
324 fn identifier() -> u32 {
325 FOOTER_IDENTIFIER_OBJECT_FOOTER_LOGICAL
326 }
327 fn encode_header(&self) -> Vec<u8> {
328 let mut vec = vec![self.version];
329 vec.append(&mut self.acquisition_start.encode_directly());
330 vec.append(&mut self.acquisition_end.encode_directly());
331 vec.append(&mut self.root_dir_filenumbers.encode_directly());
332 vec.append(&mut self.file_header_segment_numbers.encode_directly());
333 vec.append(&mut self.file_header_offsets.encode_directly());
334 vec.append(&mut self.file_footer_segment_numbers.encode_directly());
335 vec.append(&mut self.file_footer_offsets.encode_directly());
336 vec
337 }
338 fn decode_content(data: Vec<u8>) -> Result<ObjectFooterLogical> {
339 let mut cursor = Cursor::new(data);
340 let footer_version = u8::decode_directly(&mut cursor)?;
341 let acquisition_start = u64::decode_directly(&mut cursor)?;
342 let acquisition_end = u64::decode_directly(&mut cursor)?;
343 let root_dir_filenumbers = Vec::<u64>::decode_directly(&mut cursor)?;
344 let file_header_segment_numbers = HashMap::<u64, u64>::decode_directly(&mut cursor)?;
345 let file_header_offsets = HashMap::<u64, u64>::decode_directly(&mut cursor)?;
346 let file_footer_segment_numbers = HashMap::<u64, u64>::decode_directly(&mut cursor)?;
347 let file_footer_offsets = HashMap::<u64, u64>::decode_directly(&mut cursor)?;
348 Ok(ObjectFooterLogical::new(footer_version, acquisition_start, acquisition_end, root_dir_filenumbers, file_header_segment_numbers, file_header_offsets, file_footer_segment_numbers, file_footer_offsets))
349 }
350
351}