xp3/
header.rs

1/*
2 * Created on Tue Dec 15 2020
3 *
4 * Copyright (c) storycraft. Licensed under the Apache Licence 2.0.
5 */
6
7use std::io::{Read, Seek, SeekFrom, Write};
8
9use byteorder::LittleEndian;
10
11use super::{XP3Error, XP3ErrorKind, XP3_CURRENT_VER_IDENTIFIER, XP3_VERSION_IDENTIFIER};
12use byteorder::{WriteBytesExt, ReadBytesExt};
13 
14#[derive(Debug, Copy, Clone)]
15pub struct XP3Header {
16
17    version: XP3HeaderVersion
18
19}
20
21impl XP3Header {
22
23    pub fn new(version: XP3HeaderVersion) -> Self {
24        Self {
25            version
26        }
27    }
28
29    pub fn version(&self) -> XP3HeaderVersion {
30        self.version
31    }
32
33    pub fn set_version(&mut self, version: XP3HeaderVersion) {
34        self.version = version;
35    }
36
37    /// Read xp3 header from current position.
38    /// Returns read size, XP3header tuple.
39    pub fn from_bytes<T: Read + Seek>(stream: &mut T) -> Result<(u64, Self), XP3Error> {
40        let current = stream.seek(SeekFrom::Current(0))?;
41
42        let identifier = stream.read_u64::<LittleEndian>()?;
43
44        let header: XP3Header;
45        let read: u64;
46        if identifier == XP3_CURRENT_VER_IDENTIFIER {
47            let minor_version = stream.read_u32::<LittleEndian>()?;
48
49            if stream.read_u8()? != XP3_VERSION_IDENTIFIER {
50                return Err(XP3Error::new(XP3ErrorKind::InvalidHeader, None));
51            }
52            
53            header = XP3Header::new(
54                XP3HeaderVersion::Current {
55                    minor_version,
56                    index_size_offset: stream.read_u64::<LittleEndian>()?
57                }
58            );
59
60            read = 21;
61        } else {
62            stream.seek(SeekFrom::Start(current))?;
63            header = XP3Header::new(
64                XP3HeaderVersion::Old
65            );
66            read = 0;
67        }
68
69        Ok((read, header))
70    }
71
72    /// Write xp3 header to stream.
73    /// Returns written size.
74    pub fn write_bytes(&self, stream: &mut impl Write) -> Result<u64, XP3Error> {
75        let ver_written: u64;
76        match self.version {
77            XP3HeaderVersion::Old => {
78                ver_written = 0;
79            },
80
81            XP3HeaderVersion::Current { minor_version, index_size_offset } => {
82                stream.write_u64::<LittleEndian>(XP3_CURRENT_VER_IDENTIFIER)?;
83                stream.write_u32::<LittleEndian>(minor_version)?;
84                stream.write_u8(XP3_VERSION_IDENTIFIER)?;
85                stream.write_u64::<LittleEndian>(index_size_offset)?;
86                ver_written = 21;
87            }
88        }
89
90        Ok(ver_written)
91    }
92
93}
94
95#[derive(Debug, Copy, Clone)]
96/// Header starting with XP3_HEADER_IDENTIFIER is Current, otherwise Old.
97pub enum XP3HeaderVersion {
98
99    Old,
100
101    Current {
102
103        minor_version: u32,
104        index_size_offset: u64
105
106    }
107
108}