webview_bundle/
encoder.rs

1use crate::bundle::{Bundle, HEADER_MAGIC_BYTES};
2use bincode::{config, encode_to_vec};
3use std::hash::Hasher;
4use std::io::Write;
5use twox_hash::XxHash32;
6
7pub fn encode<W: Write>(bundle: &Bundle, write: W) -> crate::Result<()> {
8  Encoder::new(write).encode(bundle)?;
9  Ok(())
10}
11
12pub fn encode_bytes(bundle: &Bundle) -> crate::Result<Vec<u8>> {
13  let mut write = Vec::new();
14  encode(bundle, &mut write)?;
15  Ok(write)
16}
17
18struct Encoder<W: Write> {
19  w: W,
20}
21
22impl<W: Write> Encoder<W> {
23  fn new(w: W) -> Self {
24    Self { w }
25  }
26
27  fn encode(&mut self, bundle: &Bundle) -> crate::Result<()> {
28    let mut data = vec![];
29    data.extend(self.write_magic()?);
30    data.extend(self.write_version(&bundle)?);
31    data.extend(self.write_file_descriptors(&bundle)?);
32
33    let header_checksum = self.write_checksum(&data)?;
34    data.extend_from_slice(header_checksum.to_be_bytes().as_ref());
35
36    self.w.write_all(&bundle.data)?;
37    data.extend_from_slice(&bundle.data);
38    self.write_checksum(&data)?;
39
40    Ok(())
41  }
42
43  fn write_magic(&mut self) -> crate::Result<Vec<u8>> {
44    let bytes = HEADER_MAGIC_BYTES.to_vec();
45    self.w.write_all(&bytes)?;
46    Ok(bytes)
47  }
48
49  fn write_version(&mut self, bundle: &Bundle) -> crate::Result<Vec<u8>> {
50    let bytes = bundle.version().bytes().to_vec();
51    self.w.write_all(&bytes)?;
52    Ok(bytes)
53  }
54
55  fn write_file_descriptors(&mut self, bundle: &Bundle) -> crate::Result<Vec<u8>> {
56    let mut encoded: Vec<u8> = vec![];
57    let config = config::standard().with_big_endian();
58    let bytes = encode_to_vec(bundle.descriptors(), config).map_err(|e| crate::Error::Encode {
59      error: e,
60      message: "fail to encode file descriptors".to_string(),
61    })?;
62    let bytes_len = (bytes.len() as u32).to_be_bytes();
63    encoded.extend_from_slice(&bytes_len);
64    encoded.extend_from_slice(&bytes);
65    self.w.write_all(&encoded)?;
66    Ok(encoded)
67  }
68
69  fn write_checksum(&mut self, data: &[u8]) -> crate::Result<u32> {
70    let mut hasher = XxHash32::with_seed(0);
71    hasher.write(data);
72    let checksum = hasher.finish() as u32;
73    let checksum_bytes = checksum.to_be_bytes();
74    self.w.write_all(&checksum_bytes)?;
75    Ok(checksum)
76  }
77}
78
79#[cfg(test)]
80mod tests {
81  use super::*;
82
83  #[test]
84  fn encode_ok() {
85    let file = r#"const a = 10;"#;
86    let bundle = Bundle::builder()
87      .add_file("index.js", file.as_bytes())
88      .build();
89    let mut write = Vec::new();
90    encode(&bundle, &mut write).unwrap();
91    assert_eq!(
92      write,
93      [
94        240, 159, 140, 144, 240, 159, 142, 129, 1, 0, 0, 0, 12, 1, 8, 105, 110, 100, 101, 120, 46,
95        106, 115, 0, 18, 57, 202, 208, 23, 13, 0, 0, 0, 208, 99, 111, 110, 115, 116, 32, 97, 32,
96        61, 32, 49, 48, 59, 22, 138, 45, 182
97      ]
98    );
99  }
100}