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#[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}