tpk/
write.rs

1use crate::{Element, Entry};
2use std::{io, mem};
3use thiserror::Error;
4
5/// Representation of a TPK write error.
6#[derive(Error, Debug)]
7pub enum Error {
8    /// An unknown error happened.
9    ///
10    /// This error is "technical unknown", it should only be used in cases where the user is not
11    /// supposed to get an error but gets one anyway. More simply put, this error being returned
12    /// anywhere should be considered a bug or a feature that is not yet implemented.
13    #[error("Unknown error")]
14    Unknown,
15
16    /// A I/O error happened.
17    #[error("I/O error while writing TPK data: {source}")]
18    Io {
19        #[from]
20        source: io::Error,
21    },
22}
23
24/// Representation of a TPK write result.
25pub type Result<T> = std::result::Result<T, Error>;
26
27/// A TPK writer structure.
28///
29/// This structure holds the destination to which TPK data should be written.
30pub struct Writer<T> {
31    write: T,
32}
33
34impl<T> Writer<T>
35where
36    T: io::Write,
37{
38    /// Create a new [TPK writer][Writer].
39    pub fn new(write: T) -> Writer<T> {
40        Writer { write }
41    }
42
43    /// Write the given [Element] to this writer.
44    ///
45    /// This function will write the binary representation of the TPK element, including the type
46    /// byte, size bytes and data bytes (if any).
47    ///
48    /// Note that this is a low-level function and, as such, it makes it possible to write
49    /// semantically invalid TPK data, especially while writing [marker elements][Element::Marker].
50    pub fn write_element(&mut self, element: &Element) -> Result<()> {
51        self.write.write_all(&[element.get_type_byte()])?;
52
53        match *element {
54            Element::Marker(ref val) => {
55                let size = val.len();
56                if size > 63 {
57                    let remaining_size = size >> 6;
58                    let dynsize = dyn_size(remaining_size);
59                    self.write.write_all(dynsize.as_slice())?;
60                }
61                self.write.write_all(val.as_bytes())?;
62            }
63            Element::Integer8(val) => {
64                self.write.write_all(&[val as u8])?;
65            }
66            Element::Integer16(val) => {
67                self.write.write_all(&val.to_le_bytes())?;
68            }
69            Element::Integer32(val) => {
70                self.write.write_all(&val.to_le_bytes())?;
71            }
72            Element::Integer64(val) => {
73                self.write.write_all(&val.to_le_bytes())?;
74            }
75            Element::UInteger8(val) => {
76                self.write.write_all(&[val])?;
77            }
78            Element::UInteger16(val) => {
79                self.write.write_all(&val.to_le_bytes())?;
80            }
81            Element::UInteger32(val) => {
82                self.write.write_all(&val.to_le_bytes())?;
83            }
84            Element::UInteger64(val) => {
85                self.write.write_all(&val.to_le_bytes())?;
86            }
87            Element::Float32(val) => {
88                self.write.write_all(&val.to_le_bytes())?;
89            }
90            Element::Float64(val) => {
91                self.write.write_all(&val.to_le_bytes())?;
92            }
93            Element::String(ref val) => {
94                let bytes = val.as_bytes();
95                self.write.write_all(&static_size(bytes.len()))?;
96                self.write.write_all(bytes)?;
97            }
98            Element::Blob(ref val) => {
99                self.write.write_all(&static_size(val.len()))?;
100                self.write.write_all(val.as_slice())?;
101            }
102            _ => (),
103        };
104        Ok(())
105    }
106
107    /// Write the given [Entry] to this writer.
108    ///
109    /// This function will write the binary representation of this entry, by writing a
110    /// [marker element][Element::Marker] containing the name of the entry, as well as every data
111    /// element that this entry contains.
112    ///
113    /// Note that this is a low-level function, and as such, it is possible to write semantically
114    /// invalid TPK data using this function if the entry contains an invalid name.
115    pub fn write_entry(&mut self, entry: &Entry) -> Result<()> {
116        let marker = Element::Marker(entry.name.clone());
117        self.write_element(&marker)?;
118        for element in &entry.elements {
119            self.write_element(element)?;
120        }
121        Ok(())
122    }
123}
124
125fn static_size(size: usize) -> Vec<u8> {
126    match size {
127        0..=255 => Vec::from([size as u8]),
128        256..=65535 => Vec::from((size as u16).to_le_bytes()),
129        65536..=4294967295 => Vec::from((size as u32).to_le_bytes()),
130        _ => Vec::from((size as u64).to_le_bytes()),
131    }
132}
133
134fn dyn_size(size: usize) -> Vec<u8> {
135    if size == 0 {
136        return Vec::from([0u8]);
137    }
138
139    let fls = if size == 0 {
140        0u32
141    } else {
142        mem::size_of::<usize>() as u32 * 8u32 - size.leading_zeros()
143    };
144
145    let mut ret = Vec::with_capacity((fls / 7) as usize);
146
147    let mut size = size;
148    while size > 0 {
149        ret.push((size as u8 & 0x7F) | if size > 0x7F { 0b10000000u8 } else { 0u8 });
150        size >>= 7;
151    }
152    ret
153}