mirror of
https://github.com/iluvcapra/bwavfile.git
synced 2025-12-31 08:50:44 +00:00
prettify code
This commit is contained in:
168
src/parser.rs
168
src/parser.rs
@@ -1,15 +1,14 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::io::SeekFrom::{Current, Start};
|
||||
use std::io::{Seek, Read};
|
||||
use std::collections::HashMap;
|
||||
use std::io::{Read, Seek};
|
||||
|
||||
use byteorder::LittleEndian;
|
||||
use byteorder::ReadBytesExt;
|
||||
|
||||
use super::errors::Error;
|
||||
use super::fourcc::{FourCC, ReadFourCC};
|
||||
use super::fourcc::{RIFF_SIG, RF64_SIG, BW64_SIG, WAVE_SIG, DS64_SIG, DATA_SIG};
|
||||
use super::fourcc::{BW64_SIG, DATA_SIG, DS64_SIG, RF64_SIG, RIFF_SIG, WAVE_SIG};
|
||||
|
||||
// just for your reference...
|
||||
// RF64 documentation https://www.itu.int/dms_pubrec/itu-r/rec/bs/R-REC-BS.2088-1-201910-I!!PDF-E.pdf
|
||||
@@ -21,12 +20,26 @@ const RF64_SIZE_MARKER: u32 = 0xFF_FF_FF_FF;
|
||||
#[derive(Debug)]
|
||||
pub enum Event {
|
||||
StartParse,
|
||||
ReadHeader { signature: FourCC, length_field: u32 },
|
||||
ReadRF64Header { signature: FourCC },
|
||||
ReadDS64 {file_size: u64, long_sizes: HashMap<FourCC,u64> },
|
||||
BeginChunk { signature: FourCC, content_start: u64, content_length: u64 },
|
||||
Failed { error: Error },
|
||||
FinishParse
|
||||
ReadHeader {
|
||||
signature: FourCC,
|
||||
length_field: u32,
|
||||
},
|
||||
ReadRF64Header {
|
||||
signature: FourCC,
|
||||
},
|
||||
ReadDS64 {
|
||||
file_size: u64,
|
||||
long_sizes: HashMap<FourCC, u64>,
|
||||
},
|
||||
BeginChunk {
|
||||
signature: FourCC,
|
||||
content_start: u64,
|
||||
content_length: u64,
|
||||
},
|
||||
Failed {
|
||||
error: Error,
|
||||
},
|
||||
FinishParse,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -36,67 +49,80 @@ enum State {
|
||||
ReadyForDS64,
|
||||
ReadyForChunk { at: u64, remaining: u64 },
|
||||
Error,
|
||||
Complete
|
||||
Complete,
|
||||
}
|
||||
|
||||
pub struct Parser<R: Read + Seek> {
|
||||
stream: R,
|
||||
state: State,
|
||||
ds64state: HashMap<FourCC,u64>
|
||||
ds64state: HashMap<FourCC, u64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct ChunkIteratorItem {
|
||||
pub signature: FourCC,
|
||||
pub start: u64,
|
||||
pub length: u64
|
||||
pub length: u64,
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> Parser<R> {
|
||||
|
||||
// wraps a stream
|
||||
pub fn make(stream: R) -> Result<Self, Error> {
|
||||
let newmap: HashMap<FourCC, u64> = HashMap::new();
|
||||
let mut the_stream = stream;
|
||||
the_stream.seek(Start(0))?;
|
||||
return Ok(Parser {
|
||||
stream: the_stream,
|
||||
stream: the_stream,
|
||||
state: State::New,
|
||||
ds64state: newmap,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// pub fn into_inner(self) -> R {
|
||||
// self.stream
|
||||
// }
|
||||
|
||||
pub fn into_chunk_iterator(self) -> impl Iterator<Item = Result<ChunkIteratorItem, Error>>{
|
||||
self.filter_map({|event|
|
||||
if let Event::BeginChunk {signature , content_start, content_length } = event {
|
||||
Some(Ok(ChunkIteratorItem {signature, start: content_start, length: content_length }))
|
||||
} else if let Event::Failed { error } = event {
|
||||
Some(Err(error))
|
||||
} else {
|
||||
None
|
||||
pub fn into_chunk_iterator(self) -> impl Iterator<Item = Result<ChunkIteratorItem, Error>> {
|
||||
self.filter_map({
|
||||
|event| {
|
||||
if let Event::BeginChunk {
|
||||
signature,
|
||||
content_start,
|
||||
content_length,
|
||||
} = event
|
||||
{
|
||||
Some(Ok(ChunkIteratorItem {
|
||||
signature,
|
||||
start: content_start,
|
||||
length: content_length,
|
||||
}))
|
||||
} else if let Event::Failed { error } = event {
|
||||
Some(Err(error))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn into_chunk_list(self) -> Result<Vec<ChunkIteratorItem>,Error> {
|
||||
pub fn into_chunk_list(self) -> Result<Vec<ChunkIteratorItem>, Error> {
|
||||
let mut error = Ok(());
|
||||
|
||||
let chunks = self.into_chunk_iterator()
|
||||
let chunks = self
|
||||
.into_chunk_iterator()
|
||||
.scan(&mut error, |err, res| match res {
|
||||
Ok(ok) => Some(ok),
|
||||
Err(e) => { **err = Err(e); None }
|
||||
Err(e) => {
|
||||
**err = Err(e);
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
error?;
|
||||
|
||||
Ok( chunks )
|
||||
Ok(chunks)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> Iterator for Parser<R> {
|
||||
@@ -110,55 +136,53 @@ impl<R: Read + Seek> Iterator for Parser<R> {
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> Parser<R> {
|
||||
|
||||
fn parse_header(&mut self) -> Result<(Event,State),io::Error> {
|
||||
fn parse_header(&mut self) -> Result<(Event, State), io::Error> {
|
||||
let file_sig = self.stream.read_fourcc()?;
|
||||
let length = self.stream.read_u32::<LittleEndian>()?;
|
||||
let list_sig = self.stream.read_fourcc()?;
|
||||
|
||||
let event : Event;
|
||||
let event: Event;
|
||||
let next_state: State;
|
||||
|
||||
match (file_sig, length, list_sig) {
|
||||
(RIFF_SIG, size, WAVE_SIG) => {
|
||||
event = Event::ReadHeader {
|
||||
signature: file_sig,
|
||||
length_field: size
|
||||
length_field: size,
|
||||
};
|
||||
|
||||
next_state = State::ReadyForChunk {
|
||||
at: 12,
|
||||
remaining: (length - 4) as u64,
|
||||
};
|
||||
},
|
||||
}
|
||||
(RF64_SIG, RF64_SIZE_MARKER, WAVE_SIG) | (BW64_SIG, RF64_SIZE_MARKER, WAVE_SIG) => {
|
||||
event = Event::ReadRF64Header {
|
||||
signature: file_sig
|
||||
signature: file_sig,
|
||||
};
|
||||
|
||||
next_state = State::ReadyForDS64;
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
event = Event::Failed {
|
||||
error: Error::HeaderNotRecognized
|
||||
error: Error::HeaderNotRecognized,
|
||||
};
|
||||
next_state = State::Error;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok( (event, next_state) );
|
||||
return Ok((event, next_state));
|
||||
}
|
||||
|
||||
fn parse_ds64(&mut self) -> Result<(Event, State), Error> {
|
||||
let at :u64 = 12;
|
||||
let at: u64 = 12;
|
||||
|
||||
let ds64_sig = self.stream.read_fourcc()?;
|
||||
let ds64_size = self.stream.read_u32::<LittleEndian>()? as u64;
|
||||
let mut read :u64 = 0;
|
||||
let mut read: u64 = 0;
|
||||
|
||||
if ds64_sig != DS64_SIG {
|
||||
return Err(Error::MissingRequiredDS64);
|
||||
|
||||
} else {
|
||||
let long_file_size = self.stream.read_u64::<LittleEndian>()?;
|
||||
let long_data_size = self.stream.read_u64::<LittleEndian>()?;
|
||||
@@ -176,10 +200,10 @@ impl<R: Read + Seek> Parser<R> {
|
||||
}
|
||||
|
||||
self.ds64state.insert(DATA_SIG, long_data_size);
|
||||
|
||||
|
||||
if read < ds64_size {
|
||||
/* for some reason the ds64 chunk returned by Pro Tools is longer than
|
||||
it should be but it's all zeroes so... skip.
|
||||
it should be but it's all zeroes so... skip.
|
||||
|
||||
For the record libsndfile seems to do the same thing...
|
||||
https://github.com/libsndfile/libsndfile/blob/08d802a3d18fa19c74f38ed910d9e33f80248187/src/rf64.c#L230
|
||||
@@ -189,7 +213,7 @@ impl<R: Read + Seek> Parser<R> {
|
||||
|
||||
let event = Event::ReadDS64 {
|
||||
file_size: long_file_size,
|
||||
long_sizes : self.ds64state.clone(),
|
||||
long_sizes: self.ds64state.clone(),
|
||||
};
|
||||
|
||||
let state = State::ReadyForChunk {
|
||||
@@ -197,19 +221,17 @@ impl<R: Read + Seek> Parser<R> {
|
||||
remaining: long_file_size - (4 + 8 + ds64_size),
|
||||
};
|
||||
|
||||
return Ok( (event, state) );
|
||||
return Ok((event, state));
|
||||
}
|
||||
}
|
||||
|
||||
fn enter_chunk(&mut self, at :u64, remaining: u64) -> Result<(Event, State), io::Error> {
|
||||
|
||||
fn enter_chunk(&mut self, at: u64, remaining: u64) -> Result<(Event, State), io::Error> {
|
||||
let event;
|
||||
let state;
|
||||
|
||||
if remaining == 0 {
|
||||
event = Event::FinishParse;
|
||||
state = State::Complete;
|
||||
|
||||
} else {
|
||||
let this_fourcc = self.stream.read_fourcc()?;
|
||||
let this_size: u64;
|
||||
@@ -221,59 +243,67 @@ impl<R: Read + Seek> Parser<R> {
|
||||
this_size = self.stream.read_u32::<LittleEndian>()? as u64;
|
||||
}
|
||||
|
||||
let this_displacement :u64 = if this_size % 2 == 1 { this_size + 1 } else { this_size };
|
||||
let this_displacement: u64 = if this_size % 2 == 1 {
|
||||
this_size + 1
|
||||
} else {
|
||||
this_size
|
||||
};
|
||||
self.stream.seek(Current(this_displacement as i64))?;
|
||||
|
||||
event = Event::BeginChunk {
|
||||
signature: this_fourcc,
|
||||
content_start: at + 8,
|
||||
content_length: this_size
|
||||
content_length: this_size,
|
||||
};
|
||||
|
||||
|
||||
state = State::ReadyForChunk {
|
||||
at: at + 8 + this_displacement,
|
||||
remaining: remaining - 8 - this_displacement
|
||||
remaining: remaining - 8 - this_displacement,
|
||||
}
|
||||
}
|
||||
|
||||
return Ok( (event, state) );
|
||||
return Ok((event, state));
|
||||
}
|
||||
|
||||
fn handle_state(&mut self) -> Result<(Option<Event>, State), Error> {
|
||||
match self.state {
|
||||
State::New => {
|
||||
return Ok( ( Some(Event::StartParse) , State::ReadyForHeader) );
|
||||
},
|
||||
return Ok((Some(Event::StartParse), State::ReadyForHeader));
|
||||
}
|
||||
State::ReadyForHeader => {
|
||||
let (event, state) = self.parse_header()?;
|
||||
return Ok( ( Some(event), state ) );
|
||||
},
|
||||
return Ok((Some(event), state));
|
||||
}
|
||||
State::ReadyForDS64 => {
|
||||
let (event, state) = self.parse_ds64()?;
|
||||
return Ok( ( Some(event), state ) );
|
||||
},
|
||||
return Ok((Some(event), state));
|
||||
}
|
||||
State::ReadyForChunk { at, remaining } => {
|
||||
let (event, state) = self.enter_chunk(at, remaining)?;
|
||||
return Ok( ( Some(event), state ) );
|
||||
},
|
||||
return Ok((Some(event), state));
|
||||
}
|
||||
State::Error => {
|
||||
return Ok( ( Some(Event::FinishParse) , State::Complete ) );
|
||||
},
|
||||
return Ok((Some(Event::FinishParse), State::Complete));
|
||||
}
|
||||
State::Complete => {
|
||||
return Ok( ( None, State::Complete ) );
|
||||
return Ok((None, State::Complete));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn advance(&mut self) -> (Option<Event>, State) {
|
||||
match self.handle_state() {
|
||||
Ok(( event , state) ) => {
|
||||
Ok((event, state)) => {
|
||||
return (event, state);
|
||||
},
|
||||
}
|
||||
Err(error) => {
|
||||
return (Some(Event::Failed { error: error.into() } ), State::Error );
|
||||
return (
|
||||
Some(Event::Failed {
|
||||
error: error.into(),
|
||||
}),
|
||||
State::Error,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user