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

View File

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

View File

@ -28,14 +28,22 @@ impl VocFile {
file.read_exact(&mut signature1_buffer).unwrap();
let signature1 = std::str::from_utf8(&signature1_buffer).unwrap();
if signature1 != Self::SIGNATURE1 {
panic!("Bad file. Expected \"{}\" got \"{}\"", Self::SIGNATURE1, signature1);
panic!(
"Bad file. Expected \"{}\" got \"{}\"",
Self::SIGNATURE1,
signature1
);
}
// Signature - 1A 1A 00
let mut signature2_buffer: [u8; 3] = [0; 3];
file.read_exact(&mut signature2_buffer).unwrap();
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
@ -49,7 +57,11 @@ impl VocFile {
file.read_exact(&mut checksum_buffer).unwrap();
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 {
let block_start_address = file.stream_position().unwrap() as u32;
@ -66,7 +78,7 @@ impl VocFile {
5 => BlockType::Text,
6 => BlockType::RepeatStart,
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 {
@ -74,7 +86,12 @@ impl VocFile {
_ => {
let mut block_size_buffer: [u8; 3] = [0; 3];
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: Box<dyn Block> = match block_type {
BlockType::Terminator => Box::new(Terminator::from_stream(&mut file, block_start_address, block_end_address)),
BlockType::SoundData => Box::new(SoundData::from_stream(&mut file, 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)),
BlockType::Terminator => Box::new(Terminator::from_stream(
&mut file,
block_start_address,
block_end_address,
)),
BlockType::SoundData => Box::new(SoundData::from_stream(
&mut file,
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);
@ -129,4 +178,4 @@ impl VocFile {
drop(fp.write(&self.to_bytes()));
drop(fp.flush());
}
}
}

View File

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