parent
c9092a6e36
commit
5655b00adc
|
@ -0,0 +1 @@
|
|||
pub mod parser;
|
332
src/main.rs
332
src/main.rs
|
@ -1,335 +1,7 @@
|
|||
use nom::bytes::streaming::tag;
|
||||
use nom::number;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Codec {
|
||||
Pcm8BitUnsigned,
|
||||
Adpcm4to8,
|
||||
Adpcm3to8,
|
||||
Adpcm2to8,
|
||||
Pcm16BitSigned,
|
||||
Alaw,
|
||||
Ulaw,
|
||||
Adpcm4to16,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BlockType {
|
||||
Terminator,
|
||||
SoundData {
|
||||
sample_rate: u32,
|
||||
codec: Codec,
|
||||
data: Vec<u8>,
|
||||
},
|
||||
SoundDataContinuation {
|
||||
data: Vec<u8>,
|
||||
},
|
||||
Silence {
|
||||
length: u16,
|
||||
sample_rate: u32,
|
||||
},
|
||||
Marker {
|
||||
value: u16,
|
||||
},
|
||||
Text {
|
||||
data: Vec<u8>,
|
||||
},
|
||||
RepeatStart {
|
||||
count: u16,
|
||||
},
|
||||
RepeatEnd,
|
||||
ExtraInformation {
|
||||
sample_rate: u32,
|
||||
codec: Codec,
|
||||
channels: u8,
|
||||
},
|
||||
SoundDataNew {
|
||||
sample_rate: u32,
|
||||
bits: u8,
|
||||
channels: u8,
|
||||
codec: Codec,
|
||||
reserved: u32,
|
||||
data: Vec<u8>,
|
||||
},
|
||||
}
|
||||
|
||||
impl BlockType {
|
||||
pub fn info(&self) {
|
||||
match self {
|
||||
BlockType::Terminator => println!("Terminator"),
|
||||
BlockType::SoundData {
|
||||
sample_rate,
|
||||
codec,
|
||||
data,
|
||||
} => {
|
||||
println!(
|
||||
"Sound data: sample rate = {}, codec = {:?}, size = {}",
|
||||
sample_rate,
|
||||
codec,
|
||||
data.len()
|
||||
)
|
||||
}
|
||||
BlockType::SoundDataContinuation { data } => {
|
||||
println!("Sound data continuation: size = {}", data.len())
|
||||
}
|
||||
BlockType::Silence {
|
||||
length,
|
||||
sample_rate,
|
||||
} => {
|
||||
println!(
|
||||
"Silence: length = {}, sample rate = {}",
|
||||
length, sample_rate
|
||||
)
|
||||
}
|
||||
BlockType::Marker { value } => {
|
||||
println!("Marker: value = {}", value)
|
||||
}
|
||||
BlockType::Text { data } => {
|
||||
println!("Text: size = {}", data.len())
|
||||
}
|
||||
BlockType::RepeatStart { count } => {
|
||||
println!("Repeat: repetitions = {}", count)
|
||||
}
|
||||
BlockType::RepeatEnd => {
|
||||
println!("End repeat")
|
||||
}
|
||||
BlockType::ExtraInformation {sample_rate, codec, channels} => println!(
|
||||
"Extra information: sample rate = {}, channels = {}, codec = {:?}",
|
||||
sample_rate,
|
||||
channels,
|
||||
codec,
|
||||
),
|
||||
BlockType::SoundDataNew {
|
||||
sample_rate, bits, channels, codec, reserved, data
|
||||
} => println!(
|
||||
"Sound data (NEW): sample rate = {}, bits = {}, channels = {}, codec = {:?}, reserved: {}, size = {}",
|
||||
sample_rate,
|
||||
bits,
|
||||
channels,
|
||||
codec,
|
||||
reserved,
|
||||
data.len()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Version {
|
||||
major: u8,
|
||||
minor: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Checksum {
|
||||
value: u16,
|
||||
valid: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Voc {
|
||||
version: Version,
|
||||
checksum: Checksum,
|
||||
blocks: Vec<BlockType>,
|
||||
}
|
||||
|
||||
fn parse_sound_data(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, block_size) = number::streaming::le_u24(input)?;
|
||||
let (input, frequency_divisor) = number::streaming::le_u8(input)?;
|
||||
let (input, codec_id) = number::streaming::le_u8(input)?;
|
||||
let sample_rate: u32 = 1000000_u32 / (256_u32 - frequency_divisor as u32);
|
||||
let codec = match codec_id {
|
||||
0 => Codec::Pcm8BitUnsigned,
|
||||
1 => Codec::Adpcm4to8,
|
||||
2 => Codec::Adpcm3to8,
|
||||
3 => Codec::Adpcm2to8,
|
||||
4 => Codec::Pcm16BitSigned,
|
||||
5 => Codec::Alaw,
|
||||
6 => Codec::Ulaw,
|
||||
_ => panic!("Invalid sound format"),
|
||||
};
|
||||
let (input, data) = nom::bytes::complete::take(block_size - 2)(input)?;
|
||||
Ok((
|
||||
input,
|
||||
BlockType::SoundData {
|
||||
sample_rate,
|
||||
codec,
|
||||
data: data.to_vec(),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_sound_data_continuation(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, block_size) = number::streaming::le_u24(input)?;
|
||||
let (input, data) = nom::bytes::complete::take(block_size)(input)?;
|
||||
Ok((
|
||||
input,
|
||||
BlockType::SoundDataContinuation {
|
||||
data: data.to_vec(),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_silence(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, _) = number::streaming::le_u16(input)?;
|
||||
let (input, length) = number::streaming::le_u16(input)?;
|
||||
let (input, frequency_divisor) = number::streaming::le_u8(input)?;
|
||||
let sample_rate: u32 = 1000000_u32 / (256_u32 - frequency_divisor as u32);
|
||||
Ok((
|
||||
input,
|
||||
BlockType::Silence {
|
||||
length: length - 1,
|
||||
sample_rate,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_marker(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, _) = number::streaming::le_u16(input)?;
|
||||
let (input, value) = number::streaming::le_u16(input)?;
|
||||
Ok((input, BlockType::Marker { value }))
|
||||
}
|
||||
|
||||
fn parse_text(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, block_size) = number::streaming::le_u24(input)?;
|
||||
let (input, data) = nom::bytes::complete::take(block_size)(input)?;
|
||||
Ok((
|
||||
input,
|
||||
BlockType::Text {
|
||||
data: data.to_vec(),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_repeat_start(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, _) = number::streaming::le_u24(input)?;
|
||||
let (input, count) = number::streaming::le_u16(input)?;
|
||||
Ok((input, BlockType::RepeatStart { count }))
|
||||
}
|
||||
|
||||
fn parse_extra_information(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, _) = number::streaming::le_u24(input)?;
|
||||
let (input, frequency_divisor) = number::streaming::le_u16(input)?;
|
||||
let (input, codec_id) = number::streaming::le_u8(input)?;
|
||||
let (input, channels) = number::streaming::le_u8(input)?;
|
||||
let codec = match codec_id {
|
||||
0 => Codec::Pcm8BitUnsigned,
|
||||
1 => Codec::Adpcm4to8,
|
||||
2 => Codec::Adpcm3to8,
|
||||
3 => Codec::Adpcm2to8,
|
||||
4 => Codec::Pcm16BitSigned,
|
||||
5 => Codec::Alaw,
|
||||
6 => Codec::Ulaw,
|
||||
_ => panic!("Invalid sound format"),
|
||||
};
|
||||
let sample_rate: u32 =
|
||||
256000000_u32 / ((channels as u32 + 1) * (65536 - frequency_divisor as u32));
|
||||
Ok((
|
||||
input,
|
||||
BlockType::ExtraInformation {
|
||||
sample_rate,
|
||||
codec,
|
||||
channels,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_sound_data_new(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, block_size) = number::streaming::le_u24(input)?;
|
||||
let (input, sample_rate) = number::streaming::le_u32(input)?;
|
||||
let (input, bits) = number::streaming::le_u8(input)?;
|
||||
let (input, channels) = number::streaming::le_u8(input)?;
|
||||
let (input, codec_id) = number::streaming::le_u16(input)?;
|
||||
let (input, reserved) = number::streaming::le_u32(input)?;
|
||||
let (input, data) = nom::bytes::complete::take(block_size - 12)(input)?;
|
||||
let codec = match codec_id {
|
||||
0 => Codec::Pcm8BitUnsigned,
|
||||
1 => Codec::Adpcm4to8,
|
||||
2 => Codec::Adpcm3to8,
|
||||
3 => Codec::Adpcm2to8,
|
||||
4 => Codec::Pcm16BitSigned,
|
||||
5 => Codec::Alaw,
|
||||
6 => Codec::Ulaw,
|
||||
0x0200 => Codec::Adpcm4to16,
|
||||
_ => panic!("Invalid sound format"),
|
||||
};
|
||||
Ok((
|
||||
input,
|
||||
BlockType::SoundDataNew {
|
||||
sample_rate,
|
||||
bits,
|
||||
channels,
|
||||
codec,
|
||||
reserved,
|
||||
data: data.to_vec(),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub fn parse_block(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, block_type) = number::streaming::le_u8(input)?;
|
||||
match block_type {
|
||||
0 => Ok((input, BlockType::Terminator)),
|
||||
1 => parse_sound_data(input),
|
||||
2 => parse_sound_data_continuation(input),
|
||||
3 => parse_silence(input),
|
||||
4 => parse_marker(input),
|
||||
5 => parse_text(input),
|
||||
6 => parse_repeat_start(input),
|
||||
7 => Ok((input, BlockType::RepeatEnd)),
|
||||
8 => parse_extra_information(input),
|
||||
9 => parse_sound_data_new(input),
|
||||
_ => panic!("Invalid block type - {}", block_type),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_voc(input: &[u8]) -> nom::IResult<&[u8], Voc> {
|
||||
let (input, _) = tag("Creative Voice File")(input)?;
|
||||
let (input, _) = tag(&[0x1a, 0x1a, 0])(input)?;
|
||||
let (input, version_minor) = number::streaming::le_u8(input)?;
|
||||
let (input, version_major) = number::streaming::le_u8(input)?;
|
||||
let (input, checksum) = number::streaming::le_u16(input)?;
|
||||
// Calculate checksum from version
|
||||
let checksum2 = (!i16::from_le_bytes([version_minor, version_major]) + 0x1234) as u16;
|
||||
let valid = checksum == checksum2;
|
||||
|
||||
let mut blocks = Vec::new();
|
||||
let mut remaining_input = input;
|
||||
|
||||
loop {
|
||||
match parse_block(remaining_input) {
|
||||
Ok((input, block)) => {
|
||||
blocks.push(block);
|
||||
remaining_input = input;
|
||||
}
|
||||
Err(nom::Err::Incomplete(_)) => {
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok((
|
||||
input,
|
||||
Voc {
|
||||
version: Version {
|
||||
major: version_major,
|
||||
minor: version_minor,
|
||||
},
|
||||
checksum: Checksum {
|
||||
value: checksum,
|
||||
valid,
|
||||
},
|
||||
blocks,
|
||||
},
|
||||
))
|
||||
}
|
||||
use vocnom::parser::parse_voc;
|
||||
|
||||
fn main() {
|
||||
//let f = include_bytes!("../EDEN.MUS");
|
||||
let f = include_bytes!("../ADOOR2.VOC");
|
||||
let f = include_bytes!("../assets/GUARDIAN.VOC");
|
||||
match parse_voc(f) {
|
||||
Ok((_, voc)) => {
|
||||
println!("Version: {}.{}", voc.version.major, voc.version.minor);
|
||||
|
|
|
@ -0,0 +1,329 @@
|
|||
use nom::bytes::streaming::tag;
|
||||
use nom::number;
|
||||
|
||||
#[derive(Eq, Debug, PartialEq)]
|
||||
pub enum Codec {
|
||||
Pcm8BitUnsigned,
|
||||
Adpcm4to8,
|
||||
Adpcm3to8,
|
||||
Adpcm2to8,
|
||||
Pcm16BitSigned,
|
||||
Alaw,
|
||||
Ulaw,
|
||||
Adpcm4to16,
|
||||
}
|
||||
|
||||
#[derive(Eq, Debug, PartialEq)]
|
||||
pub enum BlockType {
|
||||
Terminator,
|
||||
SoundData {
|
||||
sample_rate: u32,
|
||||
codec: Codec,
|
||||
data: Vec<u8>,
|
||||
},
|
||||
SoundDataContinuation {
|
||||
data: Vec<u8>,
|
||||
},
|
||||
Silence {
|
||||
length: u16,
|
||||
sample_rate: u32,
|
||||
},
|
||||
Marker {
|
||||
value: u16,
|
||||
},
|
||||
Text {
|
||||
data: Vec<u8>,
|
||||
},
|
||||
RepeatStart {
|
||||
count: u16,
|
||||
},
|
||||
RepeatEnd,
|
||||
ExtraInformation {
|
||||
sample_rate: u32,
|
||||
codec: Codec,
|
||||
channels: u8,
|
||||
},
|
||||
SoundDataNew {
|
||||
sample_rate: u32,
|
||||
bits: u8,
|
||||
channels: u8,
|
||||
codec: Codec,
|
||||
reserved: u32,
|
||||
data: Vec<u8>,
|
||||
},
|
||||
}
|
||||
|
||||
impl BlockType {
|
||||
pub fn info(&self) {
|
||||
match self {
|
||||
BlockType::Terminator => println!("Terminator"),
|
||||
BlockType::SoundData {
|
||||
sample_rate,
|
||||
codec,
|
||||
data,
|
||||
} => {
|
||||
println!(
|
||||
"Sound data: sample rate = {}, codec = {:?}, size = {}",
|
||||
sample_rate,
|
||||
codec,
|
||||
data.len()
|
||||
)
|
||||
}
|
||||
BlockType::SoundDataContinuation { data } => {
|
||||
println!("Sound data continuation: size = {}", data.len())
|
||||
}
|
||||
BlockType::Silence {
|
||||
length,
|
||||
sample_rate,
|
||||
} => {
|
||||
println!(
|
||||
"Silence: length = {}, sample rate = {}",
|
||||
length, sample_rate
|
||||
)
|
||||
}
|
||||
BlockType::Marker { value } => {
|
||||
println!("Marker: value = {}", value)
|
||||
}
|
||||
BlockType::Text { data } => {
|
||||
println!("Text: size = {}", data.len())
|
||||
}
|
||||
BlockType::RepeatStart { count } => {
|
||||
println!("Repeat: repetitions = {}", count)
|
||||
}
|
||||
BlockType::RepeatEnd => {
|
||||
println!("End repeat")
|
||||
}
|
||||
BlockType::ExtraInformation { sample_rate, codec, channels } => println!(
|
||||
"Extra information: sample rate = {}, channels = {}, codec = {:?}",
|
||||
sample_rate,
|
||||
channels,
|
||||
codec,
|
||||
),
|
||||
BlockType::SoundDataNew {
|
||||
sample_rate, bits, channels, codec, reserved, data
|
||||
} => println!(
|
||||
"Sound data (NEW): sample rate = {}, bits = {}, channels = {}, codec = {:?}, reserved: {}, size = {}",
|
||||
sample_rate,
|
||||
bits,
|
||||
channels,
|
||||
codec,
|
||||
reserved,
|
||||
data.len()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Version {
|
||||
pub major: u8,
|
||||
pub minor: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Checksum {
|
||||
pub value: u16,
|
||||
pub valid: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Voc {
|
||||
pub version: Version,
|
||||
pub checksum: Checksum,
|
||||
pub blocks: Vec<BlockType>,
|
||||
}
|
||||
|
||||
fn parse_sound_data(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, block_size) = number::streaming::le_u24(input)?;
|
||||
let (input, frequency_divisor) = number::streaming::le_u8(input)?;
|
||||
let (input, codec_id) = number::streaming::le_u8(input)?;
|
||||
let sample_rate: u32 = 1000000_u32 / (256_u32 - frequency_divisor as u32);
|
||||
let codec = match codec_id {
|
||||
0 => Codec::Pcm8BitUnsigned,
|
||||
1 => Codec::Adpcm4to8,
|
||||
2 => Codec::Adpcm3to8,
|
||||
3 => Codec::Adpcm2to8,
|
||||
4 => Codec::Pcm16BitSigned,
|
||||
5 => Codec::Alaw,
|
||||
6 => Codec::Ulaw,
|
||||
_ => panic!("Invalid sound format"),
|
||||
};
|
||||
let (input, data) = nom::bytes::complete::take(block_size - 2)(input)?;
|
||||
Ok((
|
||||
input,
|
||||
BlockType::SoundData {
|
||||
sample_rate,
|
||||
codec,
|
||||
data: data.to_vec(),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_sound_data_continuation(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, block_size) = number::streaming::le_u24(input)?;
|
||||
let (input, data) = nom::bytes::complete::take(block_size)(input)?;
|
||||
Ok((
|
||||
input,
|
||||
BlockType::SoundDataContinuation {
|
||||
data: data.to_vec(),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_silence(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, _) = number::streaming::le_u16(input)?;
|
||||
let (input, length) = number::streaming::le_u16(input)?;
|
||||
let (input, frequency_divisor) = number::streaming::le_u8(input)?;
|
||||
let sample_rate: u32 = 1000000_u32 / (256_u32 - frequency_divisor as u32);
|
||||
Ok((
|
||||
input,
|
||||
BlockType::Silence {
|
||||
length: length - 1,
|
||||
sample_rate,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_marker(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, _) = number::streaming::le_u16(input)?;
|
||||
let (input, value) = number::streaming::le_u16(input)?;
|
||||
Ok((input, BlockType::Marker { value }))
|
||||
}
|
||||
|
||||
fn parse_text(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, block_size) = number::streaming::le_u24(input)?;
|
||||
let (input, data) = nom::bytes::complete::take(block_size)(input)?;
|
||||
Ok((
|
||||
input,
|
||||
BlockType::Text {
|
||||
data: data.to_vec(),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_repeat_start(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, _) = number::streaming::le_u24(input)?;
|
||||
let (input, count) = number::streaming::le_u16(input)?;
|
||||
Ok((input, BlockType::RepeatStart { count }))
|
||||
}
|
||||
|
||||
fn parse_extra_information(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, _) = number::streaming::le_u24(input)?;
|
||||
let (input, frequency_divisor) = number::streaming::le_u16(input)?;
|
||||
let (input, codec_id) = number::streaming::le_u8(input)?;
|
||||
let (input, channels) = number::streaming::le_u8(input)?;
|
||||
let codec = match codec_id {
|
||||
0 => Codec::Pcm8BitUnsigned,
|
||||
1 => Codec::Adpcm4to8,
|
||||
2 => Codec::Adpcm3to8,
|
||||
3 => Codec::Adpcm2to8,
|
||||
4 => Codec::Pcm16BitSigned,
|
||||
5 => Codec::Alaw,
|
||||
6 => Codec::Ulaw,
|
||||
_ => panic!("Invalid sound format"),
|
||||
};
|
||||
let sample_rate: u32 =
|
||||
256000000_u32 / ((channels as u32 + 1) * (65536 - frequency_divisor as u32));
|
||||
Ok((
|
||||
input,
|
||||
BlockType::ExtraInformation {
|
||||
sample_rate,
|
||||
codec,
|
||||
channels,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_sound_data_new(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, block_size) = number::streaming::le_u24(input)?;
|
||||
let (input, sample_rate) = number::streaming::le_u32(input)?;
|
||||
let (input, bits) = number::streaming::le_u8(input)?;
|
||||
let (input, channels) = number::streaming::le_u8(input)?;
|
||||
let (input, codec_id) = number::streaming::le_u16(input)?;
|
||||
let (input, reserved) = number::streaming::le_u32(input)?;
|
||||
let (input, data) = nom::bytes::complete::take(block_size - 12)(input)?;
|
||||
let codec = match codec_id {
|
||||
0 => Codec::Pcm8BitUnsigned,
|
||||
1 => Codec::Adpcm4to8,
|
||||
2 => Codec::Adpcm3to8,
|
||||
3 => Codec::Adpcm2to8,
|
||||
4 => Codec::Pcm16BitSigned,
|
||||
5 => Codec::Alaw,
|
||||
6 => Codec::Ulaw,
|
||||
0x0200 => Codec::Adpcm4to16,
|
||||
_ => panic!("Invalid sound format"),
|
||||
};
|
||||
Ok((
|
||||
input,
|
||||
BlockType::SoundDataNew {
|
||||
sample_rate,
|
||||
bits,
|
||||
channels,
|
||||
codec,
|
||||
reserved,
|
||||
data: data.to_vec(),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub fn parse_block(input: &[u8]) -> nom::IResult<&[u8], BlockType> {
|
||||
let (input, block_type) = number::streaming::le_u8(input)?;
|
||||
match block_type {
|
||||
0 => Ok((input, BlockType::Terminator)),
|
||||
1 => parse_sound_data(input),
|
||||
2 => parse_sound_data_continuation(input),
|
||||
3 => parse_silence(input),
|
||||
4 => parse_marker(input),
|
||||
5 => parse_text(input),
|
||||
6 => parse_repeat_start(input),
|
||||
7 => Ok((input, BlockType::RepeatEnd)),
|
||||
8 => parse_extra_information(input),
|
||||
9 => parse_sound_data_new(input),
|
||||
_ => panic!("Invalid block type - {}", block_type),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_voc(input: &[u8]) -> nom::IResult<&[u8], Voc> {
|
||||
let (input, _) = tag("Creative Voice File")(input)?;
|
||||
let (input, _) = tag(&[0x1a, 0x1a, 0])(input)?;
|
||||
let (input, version_minor) = number::streaming::le_u8(input)?;
|
||||
let (input, version_major) = number::streaming::le_u8(input)?;
|
||||
let (input, checksum) = number::streaming::le_u16(input)?;
|
||||
|
||||
// Calculate checksum from version
|
||||
let checksum2 = (!i16::from_le_bytes([version_minor, version_major]) + 0x1234) as u16;
|
||||
let valid = checksum == checksum2;
|
||||
|
||||
let mut blocks = Vec::new();
|
||||
let mut remaining_input = input;
|
||||
|
||||
loop {
|
||||
match parse_block(remaining_input) {
|
||||
Ok((input, block)) => {
|
||||
blocks.push(block);
|
||||
remaining_input = input;
|
||||
}
|
||||
Err(nom::Err::Incomplete(_)) => {
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok((
|
||||
input,
|
||||
Voc {
|
||||
version: Version {
|
||||
major: version_major,
|
||||
minor: version_minor,
|
||||
},
|
||||
checksum: Checksum {
|
||||
value: checksum,
|
||||
valid,
|
||||
},
|
||||
blocks,
|
||||
},
|
||||
))
|
||||
}
|
Loading…
Reference in New Issue