1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
//! IFF is a binary-interchange format developed by Electronic Arts //! for tagging binary data with a meaning. This file is made of out //! of segments referred to as so called "chunks". This format is used //! for mainly storing multimedia, eg. audio, video, midi, images. //! //! This crate provides data-structures and wrappers to manipulate this //! format quite easily by reading and decoding or writing and encoding //! from or into file-streams. //! //! # Examples //! To decode all the chunks avialable from the given reader: //! ``` //! use iffc::Decoder; //! //! fn main() { //! let inp = std::io::Cursor::new(b"RIFF\x04\x00\x00\x00WAVE"); //! let parser = Decoder::new(Box::new(inp)); //! //! for chk in parser //! { println!("{:?}: {}", chk.0, chk.1.len()); } //! } //! ``` //! //! To encode chunks into a given writer: //! ``` //! use iffc::{Encoder, Chunk}; //! //! fn main() { //! let out = std::io::Cursor::new(Vec::new()); //! let deparser = Encoder::new(Box::new(out)); //! //! deparser << Chunk(*b"RIFF", Box::new(*b"WAVE")); //! } //! ``` use std::io::{Read, Write, IoSlice, IoSliceMut}; use std::ops::{Shl}; /// An IFF chunk represents a single segment of a complete IFF /// file. Note: Even though this structure is capable of stroing /// data upto `usize` but IFF limits that to `u32` only. /// /// `0` — four-byte identity of chunk. /// `1` — byte-data encapsulated inside it. #[derive(Debug, Eq, PartialEq)] pub struct Chunk(pub [u8; 4], pub Box<[u8]>); /// A structure which wraps a reader and parses IFF chunks and /// behaves like an iterator which yields `IFFChunk` until /// an entire-chunk can't be constructed. pub struct Decoder(Box<dyn Read>); impl Decoder { pub fn new(r: Box<dyn Read>) -> Self { Self(r) } } /// A structure which wraps a writer and writes IFF chunks to it, /// by using `<<` (shift-left) with an RHS of type `IFFChunk`, also /// that operand can be chained. pub struct Encoder(Box<dyn Write>); impl Encoder { pub fn new(w: Box<dyn Write>) -> Self { Self(w) } } impl Iterator for Decoder { type Item = Chunk; fn next(&mut self) -> Option<Self::Item> { let mut id = [0u8; 4]; let mut size = [0u8; 4]; if let Err(_) = self.0.read_vectored(&mut [ IoSliceMut::new(&mut id), IoSliceMut::new(&mut size) ]) { return None }; let size = u32::from_le_bytes(size) as usize; let mut data = vec![0u8; size]; match self.0.read(&mut data) { Ok(s) => if size != s || s == 0 { return None }, Err(_) => { return None } }; Some(Chunk(id, data.into_boxed_slice())) } } impl Shl<Chunk> for Encoder { type Output = Option<Self>; fn shl(self, chunk: Chunk) -> Option<Self> { let mut sel = self; match sel.0.write_vectored(&[ IoSlice::new(&chunk.0), IoSlice::new(&(chunk.1.len() as u32) .to_le_bytes()[..]), IoSlice::new(&chunk.1) ]) { Ok(_) => Some(Self(sel.0)), Err(_) => None } } }