webview_bundle/
decoder.rs1use 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 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}