beam_file/
beam_file.rs

1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
2use std::fs::File;
3use std::io::{Cursor, Read, Write};
4use std::path::Path;
5
6use crate::chunk::Chunk;
7use crate::{Error, Result};
8
9/// A BEAM File
10///
11/// ```
12/// use beam_file::BeamFile;
13/// use beam_file::chunk::{Chunk, RawChunk};
14///
15/// let beam = BeamFile::<RawChunk>::from_file("tests/testdata/test.beam").unwrap();
16/// assert_eq!(b"Atom", beam.chunks.iter().nth(0).map(|c| c.id()).unwrap());
17/// ```
18#[derive(Debug)]
19pub struct BeamFile<C> {
20    pub chunks: Vec<C>,
21}
22impl<C: Chunk> BeamFile<C> {
23    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
24        let f = File::open(path)?;
25        Self::from_reader(f)
26    }
27    pub fn from_reader<R: Read>(mut reader: R) -> Result<Self> {
28        let expected = Header::new(0);
29        let header = Header::from_reader(&mut reader)?;
30        if header.magic_number != expected.magic_number {
31            return Err(Error::UnexpectedMagicNumber {
32                magic_number: header.magic_number,
33            });
34        }
35        if header.type_id != expected.type_id {
36            return Err(Error::UnexpectedFormType {
37                form_type: header.type_id,
38            });
39        }
40
41        let mut buf = vec![0; (header.payload_size - 4) as usize];
42        reader.read_exact(&mut buf)?;
43
44        let mut chunks = Vec::new();
45        let mut cursor = Cursor::new(&buf);
46        while cursor.position() < buf.len() as u64 {
47            chunks.push(C::decode(&mut cursor)?);
48        }
49        Ok(BeamFile { chunks })
50    }
51
52    pub fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
53        let f = File::create(path)?;
54        self.to_writer(f)
55    }
56    pub fn to_writer<W: Write>(&self, mut writer: W) -> Result<()> {
57        let mut buf = Vec::new();
58        for chunk in &self.chunks {
59            chunk.encode(&mut buf)?;
60        }
61
62        let header = Header::new(buf.len() as u32 + 4);
63        header.to_writer(&mut writer)?;
64        writer.write_all(&buf)?;
65        Ok(())
66    }
67}
68
69struct Header {
70    magic_number: [u8; 4],
71    payload_size: u32,
72    type_id: [u8; 4],
73}
74impl Header {
75    fn new(payload_size: u32) -> Self {
76        Header {
77            magic_number: *b"FOR1",
78            payload_size,
79            type_id: *b"BEAM",
80        }
81    }
82    fn from_reader<R: Read>(mut reader: R) -> Result<Self> {
83        let mut header = Self::new(0);
84        reader.read_exact(&mut header.magic_number)?;
85        header.payload_size = reader.read_u32::<BigEndian>()?;
86        reader.read_exact(&mut header.type_id)?;
87        Ok(header)
88    }
89    fn to_writer<W: Write>(&self, mut writer: W) -> Result<()> {
90        writer.write_all(&self.magic_number)?;
91        writer.write_u32::<BigEndian>(self.payload_size)?;
92        writer.write_all(&self.type_id)?;
93        Ok(())
94    }
95}