This commit is contained in:
Pedro de Oliveira 2023-04-23 01:02:11 +01:00
parent 32ea4e5503
commit cb93ab20ee
5 changed files with 184 additions and 68 deletions

View File

@ -1 +1 @@
pub mod voc; pub mod voc;

View File

@ -6,23 +6,25 @@ fn main() {
.arg_required_else_help(true) .arg_required_else_help(true)
.subcommand_value_name("COMMAND") .subcommand_value_name("COMMAND")
.subcommand_help_heading("COMMAND") .subcommand_help_heading("COMMAND")
.subcommand(clap::Command::new("info") .subcommand(
.about("Show information about the <file>") clap::Command::new("info")
.arg( .about("Show information about the <file>")
clap::arg!(<file>) .arg(
.value_parser(clap::value_parser!(String)) clap::arg!(<file>)
.required(true) .value_parser(clap::value_parser!(String))
.help("Filename"), .required(true)
), .help("Filename"),
),
) )
.subcommand(clap::Command::new("extract") .subcommand(
.about("Extract all the blocks from the <file>") clap::Command::new("extract")
.arg( .about("Extract all the blocks from the <file>")
clap::arg!(<file>) .arg(
.value_parser(clap::value_parser!(String)) clap::arg!(<file>)
.required(true) .value_parser(clap::value_parser!(String))
.help("Filename"), .required(true)
), .help("Filename"),
),
); );
let matches = cmd.get_matches(); let matches = cmd.get_matches();
@ -30,18 +32,20 @@ fn main() {
Some(("info", arguments)) => { Some(("info", arguments)) => {
let filename = arguments.get_one::<String>("file").unwrap(); let filename = arguments.get_one::<String>("file").unwrap();
let voc = voc::VocFile::from_file(filename); let voc = voc::VocFile::from_file(filename);
println!("Version {}.{} - Checksum: {}", println!(
voc.version.0, "Version {}.{} - Checksum: {}",
voc.version.1, voc.version.0,
if voc.checksum { "Valid!" } else { "Invalid!" } voc.version.1,
if voc.checksum { "Valid!" } else { "Invalid!" }
); );
for (n, block) in voc.blocks.into_iter().enumerate() { for (n, block) in voc.blocks.into_iter().enumerate() {
if let Some(block_info) = block.get_info() { if let Some(block_info) = block.get_info() {
println!("Block #{} - Start Address: {:02X?} - End Address: {:02X?} - Size {}", println!(
n, "Block #{} - Start Address: {:02X?} - End Address: {:02X?} - Size {}",
block_info.start_address, n,
block_info.end_address, block_info.start_address,
block_info.get_size() block_info.end_address,
block_info.get_size()
); );
println!("{:?}", block); println!("{:?}", block);
} }

View File

@ -54,25 +54,36 @@ pub struct Terminator {
impl Terminator { impl Terminator {
#[cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))] #[cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
pub fn new() -> Self { Self { info: None, block_type: BlockType::Terminator } } pub fn new() -> Self {
pub fn from_stream(_fp: &mut File, start_address: u32, end_address: u32) -> Self
{
Self { Self {
info: Some(BlockInfo { block_type: BlockType::Terminator, start_address, end_address }), info: None,
block_type: BlockType::Terminator,
}
}
pub fn from_stream(_fp: &mut File, start_address: u32, end_address: u32) -> Self {
Self {
info: Some(BlockInfo {
block_type: BlockType::Terminator,
start_address,
end_address,
}),
block_type: BlockType::Terminator, block_type: BlockType::Terminator,
} }
} }
} }
impl Block for Terminator { impl Block for Terminator {
fn to_bytes(&self) -> Vec<u8> { vec![self.block_type as u8] } fn to_bytes(&self) -> Vec<u8> {
fn get_info(&self) -> &Option<BlockInfo> { &self.info } vec![self.block_type as u8]
}
fn get_info(&self) -> &Option<BlockInfo> {
&self.info
}
} }
impl fmt::Debug for Terminator { impl fmt::Debug for Terminator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Terminator") f.debug_struct("Terminator").finish()
.finish()
} }
} }
@ -113,7 +124,7 @@ impl SoundData {
5 => Codec::Alaw, 5 => Codec::Alaw,
6 => Codec::Ulaw, 6 => Codec::Ulaw,
7 => Codec::Adpcm4to16, 7 => Codec::Adpcm4to16,
_ => panic!("Bad Sound format. Got {}", codec_buffer[0]) _ => panic!("Bad Sound format. Got {}", codec_buffer[0]),
}; };
let address = fp.stream_position().unwrap() as u32; let address = fp.stream_position().unwrap() as u32;
@ -121,7 +132,11 @@ impl SoundData {
drop(fp.read(&mut data)); drop(fp.read(&mut data));
Self { Self {
info: Some(BlockInfo { block_type: BlockType::SoundData, start_address, end_address }), info: Some(BlockInfo {
block_type: BlockType::SoundData,
start_address,
end_address,
}),
block_type: BlockType::SoundData, block_type: BlockType::SoundData,
sample_rate, sample_rate,
codec, codec,
@ -148,7 +163,9 @@ impl Block for SoundData {
result result
} }
fn get_info(&self) -> &Option<BlockInfo> { &self.info } fn get_info(&self) -> &Option<BlockInfo> {
&self.info
}
} }
impl fmt::Debug for SoundData { impl fmt::Debug for SoundData {
@ -183,7 +200,11 @@ impl SoundDataContinuation {
drop(fp.read(&mut data)); drop(fp.read(&mut data));
Self { Self {
info: Some(BlockInfo { block_type: BlockType::SoundDataContinuation, start_address, end_address }), info: Some(BlockInfo {
block_type: BlockType::SoundDataContinuation,
start_address,
end_address,
}),
block_type: BlockType::SoundDataContinuation, block_type: BlockType::SoundDataContinuation,
data, data,
} }
@ -203,7 +224,9 @@ impl Block for SoundDataContinuation {
result.extend_from_slice(&self.data); result.extend_from_slice(&self.data);
result result
} }
fn get_info(&self) -> &Option<BlockInfo> { &self.info } fn get_info(&self) -> &Option<BlockInfo> {
&self.info
}
} }
impl fmt::Debug for SoundDataContinuation { impl fmt::Debug for SoundDataContinuation {
@ -242,7 +265,11 @@ impl Silence {
let sample_rate: u32 = 1000000u32 / (256u32 - frequency_divisor_buffer[0] as u32); let sample_rate: u32 = 1000000u32 / (256u32 - frequency_divisor_buffer[0] as u32);
Self { Self {
info: Some(BlockInfo { block_type: BlockType::Silence, start_address, end_address }), info: Some(BlockInfo {
block_type: BlockType::Silence,
start_address,
end_address,
}),
block_type: BlockType::Silence, block_type: BlockType::Silence,
length, length,
sample_rate, sample_rate,
@ -268,7 +295,9 @@ impl Block for Silence {
result result
} }
fn get_info(&self) -> &Option<BlockInfo> { &self.info } fn get_info(&self) -> &Option<BlockInfo> {
&self.info
}
} }
impl fmt::Debug for Silence { impl fmt::Debug for Silence {
@ -302,7 +331,11 @@ impl Marker {
let value = u16::from_le_bytes(value_buffer); let value = u16::from_le_bytes(value_buffer);
Self { Self {
info: Some(BlockInfo { block_type: BlockType::Marker, start_address, end_address }), info: Some(BlockInfo {
block_type: BlockType::Marker,
start_address,
end_address,
}),
block_type: BlockType::Marker, block_type: BlockType::Marker,
value, value,
} }
@ -325,7 +358,9 @@ impl Block for Marker {
result result
} }
fn get_info(&self) -> &Option<BlockInfo> { &self.info } fn get_info(&self) -> &Option<BlockInfo> {
&self.info
}
} }
impl fmt::Debug for Marker { impl fmt::Debug for Marker {
@ -345,14 +380,24 @@ pub struct Text {
} }
impl Text { impl Text {
pub fn new(data: Vec<u8>) -> Self { Self { info: None, block_type: BlockType::Text, data } } pub fn new(data: Vec<u8>) -> Self {
Self {
info: None,
block_type: BlockType::Text,
data,
}
}
pub fn from_stream(fp: &mut File, start_address: u32, end_address: u32) -> Self { pub fn from_stream(fp: &mut File, start_address: u32, end_address: u32) -> Self {
let address = fp.stream_position().unwrap() as u32; let address = fp.stream_position().unwrap() as u32;
let mut data: Vec<u8> = vec![0; (end_address - address) as usize]; let mut data: Vec<u8> = vec![0; (end_address - address) as usize];
drop(fp.read(&mut data)); drop(fp.read(&mut data));
Self { Self {
info: Some(BlockInfo { block_type: BlockType::Text, start_address, end_address }), info: Some(BlockInfo {
block_type: BlockType::Text,
start_address,
end_address,
}),
block_type: BlockType::Text, block_type: BlockType::Text,
data, data,
} }
@ -374,7 +419,9 @@ impl Block for Text {
result result
} }
fn get_info(&self) -> &Option<BlockInfo> { &self.info } fn get_info(&self) -> &Option<BlockInfo> {
&self.info
}
} }
impl fmt::Debug for Text { impl fmt::Debug for Text {
@ -407,7 +454,11 @@ impl RepeatStart {
let count = u16::from_le_bytes(count_buffer) + 1; let count = u16::from_le_bytes(count_buffer) + 1;
Self { Self {
info: Some(BlockInfo { block_type: BlockType::RepeatStart, start_address, end_address }), info: Some(BlockInfo {
block_type: BlockType::RepeatStart,
start_address,
end_address,
}),
block_type: BlockType::RepeatStart, block_type: BlockType::RepeatStart,
count, count,
} }
@ -430,7 +481,9 @@ impl Block for RepeatStart {
result result
} }
fn get_info(&self) -> &Option<BlockInfo> { &self.info } fn get_info(&self) -> &Option<BlockInfo> {
&self.info
}
} }
impl fmt::Debug for RepeatStart { impl fmt::Debug for RepeatStart {
@ -450,10 +503,19 @@ pub struct RepeatEnd {
impl RepeatEnd { impl RepeatEnd {
#[cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))] #[cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
pub fn new() -> Self { Self { info: None, block_type: BlockType::RepeatEnd } } pub fn new() -> Self {
Self {
info: None,
block_type: BlockType::RepeatEnd,
}
}
pub fn from_stream(_fp: &mut File, start_address: u32, end_address: u32) -> Self { pub fn from_stream(_fp: &mut File, start_address: u32, end_address: u32) -> Self {
Self { Self {
info: Some(BlockInfo { block_type: BlockType::RepeatEnd, start_address, end_address }), info: Some(BlockInfo {
block_type: BlockType::RepeatEnd,
start_address,
end_address,
}),
block_type: BlockType::RepeatEnd, block_type: BlockType::RepeatEnd,
} }
} }
@ -463,12 +525,13 @@ impl Block for RepeatEnd {
fn to_bytes(&self) -> Vec<u8> { fn to_bytes(&self) -> Vec<u8> {
vec![self.block_type as u8] vec![self.block_type as u8]
} }
fn get_info(&self) -> &Option<BlockInfo> { &self.info } fn get_info(&self) -> &Option<BlockInfo> {
&self.info
}
} }
impl fmt::Debug for RepeatEnd { impl fmt::Debug for RepeatEnd {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RepeatEnd") f.debug_struct("RepeatEnd").finish()
.finish()
} }
} }

View File

@ -28,14 +28,22 @@ impl VocFile {
file.read_exact(&mut signature1_buffer).unwrap(); file.read_exact(&mut signature1_buffer).unwrap();
let signature1 = std::str::from_utf8(&signature1_buffer).unwrap(); let signature1 = std::str::from_utf8(&signature1_buffer).unwrap();
if signature1 != Self::SIGNATURE1 { if signature1 != Self::SIGNATURE1 {
panic!("Bad file. Expected \"{}\" got \"{}\"", Self::SIGNATURE1, signature1); panic!(
"Bad file. Expected \"{}\" got \"{}\"",
Self::SIGNATURE1,
signature1
);
} }
// Signature - 1A 1A 00 // Signature - 1A 1A 00
let mut signature2_buffer: [u8; 3] = [0; 3]; let mut signature2_buffer: [u8; 3] = [0; 3];
file.read_exact(&mut signature2_buffer).unwrap(); file.read_exact(&mut signature2_buffer).unwrap();
if signature2_buffer != Self::SIGNATURE2 { if signature2_buffer != Self::SIGNATURE2 {
panic!("Bad file. Expected {:02X?} got {:02X?}", Self::SIGNATURE2, signature2_buffer); panic!(
"Bad file. Expected {:02X?} got {:02X?}",
Self::SIGNATURE2,
signature2_buffer
);
} }
// Version // Version
@ -49,7 +57,11 @@ impl VocFile {
file.read_exact(&mut checksum_buffer).unwrap(); file.read_exact(&mut checksum_buffer).unwrap();
let checksum_result = checksum_buffer == Self::checksum(version_int); let checksum_result = checksum_buffer == Self::checksum(version_int);
let mut voc_file = VocFile { version, checksum: checksum_result, blocks: Vec::new() }; let mut voc_file = VocFile {
version,
checksum: checksum_result,
blocks: Vec::new(),
};
loop { loop {
let block_start_address = file.stream_position().unwrap() as u32; let block_start_address = file.stream_position().unwrap() as u32;
@ -66,7 +78,7 @@ impl VocFile {
5 => BlockType::Text, 5 => BlockType::Text,
6 => BlockType::RepeatStart, 6 => BlockType::RepeatStart,
7 => BlockType::RepeatEnd, 7 => BlockType::RepeatEnd,
_ => panic!("Bad block type. Got {}", block_type_buffer[0]) _ => panic!("Bad block type. Got {}", block_type_buffer[0]),
}; };
let block_size = match block_type { let block_size = match block_type {
@ -74,7 +86,12 @@ impl VocFile {
_ => { _ => {
let mut block_size_buffer: [u8; 3] = [0; 3]; let mut block_size_buffer: [u8; 3] = [0; 3];
file.read_exact(&mut block_size_buffer).unwrap(); file.read_exact(&mut block_size_buffer).unwrap();
u32::from_le_bytes([block_size_buffer[0], block_size_buffer[1], block_size_buffer[2], 0]) u32::from_le_bytes([
block_size_buffer[0],
block_size_buffer[1],
block_size_buffer[2],
0,
])
} }
}; };
@ -82,14 +99,46 @@ impl VocFile {
let block_end_address = current_address + block_size; let block_end_address = current_address + block_size;
let block: Box<dyn Block> = match block_type { let block: Box<dyn Block> = match block_type {
BlockType::Terminator => Box::new(Terminator::from_stream(&mut file, block_start_address, block_end_address)), BlockType::Terminator => Box::new(Terminator::from_stream(
BlockType::SoundData => Box::new(SoundData::from_stream(&mut file, block_start_address, block_end_address)), &mut file,
BlockType::SoundDataContinuation => Box::new(SoundDataContinuation::from_stream(&mut file, block_start_address, block_end_address)), block_start_address,
BlockType::Silence => Box::new(Silence::from_stream(&mut file, block_start_address, block_end_address)), block_end_address,
BlockType::Marker => Box::new(Marker::from_stream(&mut file, block_start_address, block_end_address)), )),
BlockType::Text => Box::new(Text::from_stream(&mut file, block_start_address, block_end_address)), BlockType::SoundData => Box::new(SoundData::from_stream(
BlockType::RepeatStart => Box::new(RepeatStart::from_stream(&mut file, block_start_address, block_end_address)), &mut file,
BlockType::RepeatEnd => Box::new(RepeatEnd::from_stream(&mut file, block_start_address, block_end_address)), block_start_address,
block_end_address,
)),
BlockType::SoundDataContinuation => Box::new(SoundDataContinuation::from_stream(
&mut file,
block_start_address,
block_end_address,
)),
BlockType::Silence => Box::new(Silence::from_stream(
&mut file,
block_start_address,
block_end_address,
)),
BlockType::Marker => Box::new(Marker::from_stream(
&mut file,
block_start_address,
block_end_address,
)),
BlockType::Text => Box::new(Text::from_stream(
&mut file,
block_start_address,
block_end_address,
)),
BlockType::RepeatStart => Box::new(RepeatStart::from_stream(
&mut file,
block_start_address,
block_end_address,
)),
BlockType::RepeatEnd => Box::new(RepeatEnd::from_stream(
&mut file,
block_start_address,
block_end_address,
)),
}; };
voc_file.blocks.push(block); voc_file.blocks.push(block);
@ -129,4 +178,4 @@ impl VocFile {
drop(fp.write(&self.to_bytes())); drop(fp.write(&self.to_bytes()));
drop(fp.flush()); drop(fp.flush());
} }
} }

View File

@ -21,4 +21,4 @@ mod tests {
assert_eq!(0xB5, block.end_address); assert_eq!(0xB5, block.end_address);
assert_eq!(155, block.get_size()); assert_eq!(155, block.get_size());
} }
} }