mirror of
https://github.com/iluvcapra/bwavfile.git
synced 2025-12-31 08:50:44 +00:00
145 lines
4.8 KiB
Rust
145 lines
4.8 KiB
Rust
use super::parser::{Parser};
|
|
use super::fourcc::{FourCC, FMT__SIG,DATA_SIG, BEXT_SIG, JUNK_SIG, FLLR_SIG};
|
|
use super::errors::Error as ParserError;
|
|
use super::wavereader::{WaveReader};
|
|
|
|
use std::io::{Read,Seek};
|
|
|
|
impl<R:Read + Seek> WaveReader<R> {
|
|
/**
|
|
* Returns without `Err` if the source meets the minimum standard of
|
|
* readability by a permissive client:
|
|
* 1. `fmt` chunk and `data` chunk are present
|
|
* 1. `fmt` chunk appears before `data` chunk
|
|
*/
|
|
pub fn validate_readable(&mut self) -> Result<(), ParserError> {
|
|
let (fmt_pos, _) = self.get_chunk_extent_at_index(FMT__SIG, 0)?;
|
|
let (data_pos, _) = self.get_chunk_extent_at_index(DATA_SIG, 0)?;
|
|
|
|
if fmt_pos < data_pos {
|
|
Ok(())
|
|
} else {
|
|
Err( ParserError::FmtChunkAfterData)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate minimal WAVE file
|
|
*
|
|
* Returns without `Err` the source is `validate_readable` AND
|
|
*
|
|
* - Contains _only_ a `fmt` chunk and `data` chunk, with no other chunks present
|
|
* - is not an RF64/BW64
|
|
*
|
|
* Some clients require a WAVE file to only contain format and data without any other
|
|
* metadata and this function is provided to validate this condition.
|
|
*
|
|
* ```
|
|
* # use bwavfile::WaveReader;
|
|
*
|
|
* let mut w = WaveReader::open("tests/media/ff_minimal.wav").unwrap();
|
|
* w.validate_minimal().expect("Minimal wav did not validate not minimal!");
|
|
* ```
|
|
*
|
|
* ```
|
|
* # use bwavfile::WaveReader;
|
|
*
|
|
* let mut x = WaveReader::open("tests/media/pt_24bit_51.wav").unwrap();
|
|
* x.validate_minimal().expect_err("Complex WAV validated minimal!");
|
|
* ```
|
|
*/
|
|
pub fn validate_minimal(&mut self) -> Result<(), ParserError> {
|
|
self.validate_readable()?;
|
|
|
|
let chunk_fourccs : Vec<FourCC> = Parser::make(&mut self.inner)?
|
|
.into_chunk_list()?.iter().map(|c| c.signature ).collect();
|
|
|
|
if chunk_fourccs == vec![FMT__SIG, DATA_SIG] {
|
|
Ok(())
|
|
} else {
|
|
Err( ParserError::NotMinimalWaveFile )
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate Broadcast-WAVE file format
|
|
*
|
|
* Returns without `Err` if `validate_readable()` and file contains a
|
|
* Broadcast-WAV metadata record (a `bext` chunk).
|
|
*
|
|
* ```
|
|
* # use bwavfile::WaveReader;
|
|
*
|
|
* let mut w = WaveReader::open("tests/media/ff_bwav_stereo.wav").unwrap();
|
|
* w.validate_broadcast_wave().expect("BWAVE file did not validate BWAVE");
|
|
*
|
|
* let mut x = WaveReader::open("tests/media/pt_24bit.wav").unwrap();
|
|
* x.validate_broadcast_wave().expect("BWAVE file did not validate BWAVE");
|
|
*
|
|
* let mut y = WaveReader::open("tests/media/audacity_16bit.wav").unwrap();
|
|
* y.validate_broadcast_wave().expect_err("Plain WAV file DID validate BWAVE");
|
|
* ```
|
|
*/
|
|
pub fn validate_broadcast_wave(&mut self) -> Result<(), ParserError> {
|
|
self.validate_readable()?;
|
|
let (_, _) = self.get_chunk_extent_at_index(BEXT_SIG, 0)?;
|
|
Ok(())
|
|
}
|
|
|
|
/**
|
|
* Verify data is aligned to a block boundary
|
|
*
|
|
* Returns without `Err` if `validate_readable()` and the start of the
|
|
* `data` chunk's content begins at 0x4000.
|
|
*/
|
|
pub fn validate_data_chunk_alignment(&mut self) -> Result<() , ParserError> {
|
|
self.validate_readable()?;
|
|
let (start, _) = self.get_chunk_extent_at_index(DATA_SIG, 0)?;
|
|
if start == 0x4000 {
|
|
Ok(())
|
|
} else {
|
|
Err(ParserError::DataChunkNotAligned)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns without `Err` if:
|
|
* - `validate_readable()`
|
|
* - there is a `JUNK` or `FLLR` immediately at the beginning of the chunk
|
|
* list adequately large enough to be overwritten by a `ds64` (96 bytes)
|
|
* - `data` is the final chunk
|
|
*/
|
|
pub fn validate_prepared_for_append(&mut self) -> Result<(), ParserError> {
|
|
self.validate_readable()?;
|
|
|
|
let chunks = Parser::make(&mut self.inner)?.into_chunk_list()?;
|
|
let ds64_space_required = 92;
|
|
|
|
let eligible_filler_chunks = chunks.iter()
|
|
.take_while(|c| c.signature == JUNK_SIG || c.signature == FLLR_SIG);
|
|
|
|
let filler = eligible_filler_chunks
|
|
.enumerate()
|
|
.fold(0, |accum, (n, item)| if n == 0 { accum + item.length } else {accum + item.length + 8});
|
|
|
|
if filler < ds64_space_required {
|
|
Err(ParserError::InsufficientDS64Reservation {expected: ds64_space_required, actual: filler})
|
|
} else {
|
|
let data_pos = chunks.iter().position(|c| c.signature == DATA_SIG);
|
|
|
|
match data_pos {
|
|
Some(p) if p == chunks.len() - 1 => Ok(()),
|
|
_ => Err(ParserError::DataChunkNotPreparedForAppend)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|