webview_bundle/
decoder.rs

1use crate::bundle::{
2  Bundle, FileDescriptor, Version, FILE_DESCRIPTORS_SIZE_BYTES_LENGTH, HEADER_MAGIC_BYTES,
3  VERSION_BYTES_LENGTH,
4};
5use bincode::{config, decode_from_slice};
6use std::io::{Cursor, Read};
7
8pub fn decode(buf: impl AsRef<[u8]>) -> crate::Result<Bundle> {
9  Decoder::new(&buf).decode()
10}
11
12struct Decoder<T> {
13  c: Cursor<T>,
14}
15
16impl<T> Decoder<T> {
17  fn new(buf: T) -> Self {
18    Self {
19      c: Cursor::new(buf),
20    }
21  }
22}
23
24impl<T: AsRef<[u8]>> Decoder<T> {
25  fn decode(&mut self) -> crate::Result<Bundle> {
26    // TODO: check checksum?
27    self.read_magic_bytes()?;
28    let version = self.read_version()?;
29    let descriptors = self.read_file_descriptors()?;
30    let mut data = Vec::new();
31    self.c.read_to_end(&mut data)?;
32    let bundle = Bundle {
33      version,
34      descriptors,
35      data,
36    };
37    Ok(bundle)
38  }
39
40  fn read_magic_bytes(&mut self) -> crate::Result<()> {
41    let mut buf = [0; HEADER_MAGIC_BYTES.len()];
42    self.c.read_exact(&mut buf)?;
43    if buf != HEADER_MAGIC_BYTES {
44      return Err(crate::Error::InvalidMagic);
45    }
46    Ok(())
47  }
48
49  fn read_version(&mut self) -> crate::Result<Version> {
50    let mut buf = [0; VERSION_BYTES_LENGTH];
51    self.c.read_exact(&mut buf)?;
52    if &buf == Version::Version1.bytes() {
53      return Ok(Version::Version1);
54    }
55    Err(crate::Error::InvalidVersion)
56  }
57
58  fn read_file_descriptors(&mut self) -> crate::Result<Vec<FileDescriptor>> {
59    let mut size_buf = [0; FILE_DESCRIPTORS_SIZE_BYTES_LENGTH];
60    self.c.read_exact(&mut size_buf)?;
61    let size = u32::from_be_bytes(AsRef::<[u8]>::as_ref(&size_buf).try_into().unwrap());
62
63    let mut descriptors_buf = vec![0; size as usize];
64    self.c.read_exact(&mut descriptors_buf)?;
65    let config = config::standard().with_big_endian();
66    let (file_descriptors, _): (Vec<FileDescriptor>, _) =
67      decode_from_slice(&descriptors_buf, config)?;
68    Ok(file_descriptors)
69  }
70}
71
72#[cfg(test)]
73mod tests {
74  use super::*;
75  use crate::encoder::encode_bytes;
76  use std::path::Path;
77
78  #[test]
79  fn encode_and_decode() {
80    let path = Path::new("index.js");
81    let file = r#"const a = 10;"#;
82    let bundle = Bundle::builder().add_file(path, file.as_bytes()).build();
83    let encoded = encode_bytes(&bundle).unwrap();
84    let decoded = decode(encoded).unwrap();
85    assert_eq!(bundle, decoded);
86  }
87
88  #[test]
89  fn invalid_magic() {
90    assert!(matches!(
91      decode(vec![0, 0, 0, 0, 0, 0, 0, 0]).unwrap_err(),
92      crate::Error::InvalidMagic,
93    ));
94  }
95}