diff --git a/src/main.rs b/src/main.rs index 3b84a46..6231225 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,25 +7,54 @@ fn main() { .subcommand_value_name("COMMAND") .subcommand_help_heading("COMMAND") .subcommand(clap::Command::new("info") - .about("Show information about the ") - .arg( - clap::arg!() - .value_parser(clap::value_parser!(String)) - .required(true) - .help("Filename"), - ), + .about("Show information about the ") + .arg( + clap::arg!() + .value_parser(clap::value_parser!(String)) + .required(true) + .help("Filename"), + ), + ) + .subcommand(clap::Command::new("extract") + .about("Extract all the blocks from the ") + .arg( + clap::arg!() + .value_parser(clap::value_parser!(String)) + .required(true) + .help("Filename"), + ), ); let matches = cmd.get_matches(); match matches.subcommand() { Some(("info", arguments)) => { + let filename = arguments.get_one::("file").unwrap(); + let voc = voc::VocFile::from_file(filename); + 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); + } + } + } + Some(("extract", _arguments)) => { + /* let filename = arguments.get_one::("file").unwrap(); let voc = voc::VocFile::from_file(filename); println!("{:?}", voc); voc.to_file("lulz.voc"); + */ } _ => unreachable!("parser should ensure only valid subcommand names are used"), }; - - } diff --git a/src/voc.rs b/src/voc.rs index 1f63419..cf9a919 100644 --- a/src/voc.rs +++ b/src/voc.rs @@ -31,6 +31,7 @@ pub enum BlockType { #[derive(Debug)] pub struct VocFile { pub version: (u8, u8), + pub checksum: bool, pub blocks: Vec, } @@ -65,13 +66,13 @@ impl VocFile { let mut checksum_buffer: [u8; 2] = [0; 2]; drop(fp.read(&mut checksum_buffer)); let checksum = (!version_int + 0x1234).to_le_bytes(); - if checksum_buffer != checksum { - panic!("Bad file. Expected {:02X?} got {:02X?}", checksum, checksum_buffer); - } + let checksum_result = checksum_buffer == checksum; - let mut voc = VocFile { version, blocks: Vec::new() }; + let mut voc = VocFile { version, checksum: checksum_result, blocks: Vec::new() }; loop { + let block_start_address = fp.seek(SeekFrom::Current(0)).unwrap() as u32; + // Block Type let mut block_type_buffer: [u8; 1] = [0]; drop(fp.read(&mut block_type_buffer)); @@ -98,41 +99,41 @@ impl VocFile { ); } - let address = fp.seek(SeekFrom::Current(0)).unwrap() as u32; - let end_address = address + block_size; + let current_address = fp.seek(SeekFrom::Current(0)).unwrap() as u32; + let block_end_address = current_address + block_size; match block_type { BlockType::Terminator => { - let block = Terminator::from_stream(&mut fp, end_address); + let block = Terminator::from_stream(&mut fp, block_start_address, block_end_address); voc.blocks.push(Box::new(block)); break; } BlockType::SoundData => { - let block = SoundData::from_stream(&mut fp, end_address); + let block = SoundData::from_stream(&mut fp, block_start_address, block_end_address); voc.blocks.push(Box::new(block)); } BlockType::SoundDataContinuation => { - let block = SoundDataContinuation::from_stream(&mut fp, end_address); + let block = SoundDataContinuation::from_stream(&mut fp, block_start_address, block_end_address); voc.blocks.push(Box::new(block)); } BlockType::Silence => { - let block = Silence::from_stream(&mut fp, end_address); + let block = Silence::from_stream(&mut fp, block_start_address, block_end_address); voc.blocks.push(Box::new(block)); } BlockType::Marker => { - let block = Marker::from_stream(&mut fp, end_address); + let block = Marker::from_stream(&mut fp, block_start_address, block_end_address); voc.blocks.push(Box::new(block)); } BlockType::Text => { - let block = Text::from_stream(&mut fp, end_address); + let block = Text::from_stream(&mut fp, block_start_address, block_end_address); voc.blocks.push(Box::new(block)); } BlockType::RepeatStart => { - let block = RepeatStart::from_stream(&mut fp, end_address); + let block = RepeatStart::from_stream(&mut fp, block_start_address, block_end_address); voc.blocks.push(Box::new(block)); } BlockType::RepeatEnd => { - let block = RepeatEnd::from_stream(&mut fp, end_address); + let block = RepeatEnd::from_stream(&mut fp, block_start_address, block_end_address); voc.blocks.push(Box::new(block)); } } @@ -177,28 +178,41 @@ type BlockT = Box; pub trait Block: fmt::Debug { fn to_bytes(&self) -> Vec; + fn get_info(&self) -> &Option; +} + +pub struct BlockInfo { + pub start_address: u32, + pub end_address: u32, +} + +impl BlockInfo { + pub fn get_size(&self) -> u32 { + self.end_address - self.start_address + } } // Terminator pub struct Terminator { + info: Option, block_type: BlockType, } impl Terminator { - pub fn new() -> Self { - Self { block_type: BlockType::Terminator } - } - - pub fn from_stream(_fp: &mut File, _end_address: u32) -> Self { - Self::new() + 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 + { + Self { + info: Some(BlockInfo { start_address, end_address }), + block_type: BlockType::Terminator, + } } } impl Block for Terminator { - fn to_bytes(&self) -> Vec { - vec![self.block_type as u8] - } + fn to_bytes(&self) -> Vec { vec![self.block_type as u8] } + fn get_info(&self) -> &Option { &self.info } } impl fmt::Debug for Terminator { @@ -211,15 +225,17 @@ impl fmt::Debug for Terminator { // SoundData pub struct SoundData { + info: Option, block_type: BlockType, - pub sample_rate: u32, - pub codec: Codec, - pub data: Vec, + sample_rate: u32, + codec: Codec, + data: Vec, } impl SoundData { pub fn new(sample_rate: u32, codec: Codec, data: Vec) -> Self { Self { + info: None, block_type: BlockType::SoundData, sample_rate, codec, @@ -227,7 +243,7 @@ impl SoundData { } } - pub fn from_stream(fp: &mut File, end_address: u32) -> Self { + pub fn from_stream(fp: &mut File, start_address: u32, end_address: u32) -> Self { let mut frequency_divisor_buffer: [u8; 1] = [0]; drop(fp.read(&mut frequency_divisor_buffer)); let sample_rate: u32 = 1000000u32 / (256u32 - frequency_divisor_buffer[0] as u32); @@ -250,7 +266,13 @@ impl SoundData { let mut data: Vec = vec![0; (end_address - address) as usize]; drop(fp.read(&mut data)); - Self::new(sample_rate, codec, data) + Self { + info: Some(BlockInfo { start_address, end_address }), + block_type: BlockType::SoundData, + sample_rate, + codec, + data, + } } } @@ -272,6 +294,7 @@ impl Block for SoundData { result } + fn get_info(&self) -> &Option { &self.info } } impl fmt::Debug for SoundData { @@ -287,24 +310,29 @@ impl fmt::Debug for SoundData { // SoundDataContinuation pub struct SoundDataContinuation { - pub block_type: BlockType, - pub data: Vec, + info: Option, + block_type: BlockType, + data: Vec, } impl SoundDataContinuation { pub fn new(data: Vec) -> Self { Self { + info: None, block_type: BlockType::SoundDataContinuation, data, } } - - pub fn from_stream(fp: &mut File, end_address: u32) -> Self { + pub fn from_stream(fp: &mut File, start_address: u32, end_address: u32) -> Self { let address = fp.seek(SeekFrom::Current(0)).unwrap() as u32; let mut data: Vec = vec![0; (end_address - address) as usize]; drop(fp.read(&mut data)); - Self::new(data) + Self { + info: Some(BlockInfo { start_address, end_address }), + block_type: BlockType::SoundDataContinuation, + data, + } } } @@ -315,12 +343,13 @@ impl Block for SoundDataContinuation { self.block_type as u8, size_bytes[0], size_bytes[1], - size_bytes[2] + size_bytes[2], ]; result.extend_from_slice(&self.data); result } + fn get_info(&self) -> &Option { &self.info } } impl fmt::Debug for SoundDataContinuation { @@ -334,21 +363,22 @@ impl fmt::Debug for SoundDataContinuation { // Silence pub struct Silence { - pub block_type: BlockType, - pub length: u16, - pub sample_rate: u32, + info: Option, + block_type: BlockType, + length: u16, + sample_rate: u32, } impl Silence { pub fn new(length: u16, sample_rate: u32) -> Self { Self { + info: None, block_type: BlockType::Silence, length, - sample_rate + sample_rate, } } - - pub fn from_stream(fp: &mut File, _end_address: u32) -> Self { + pub fn from_stream(fp: &mut File, start_address: u32, end_address: u32) -> Self { let mut length_buffer: [u8; 2] = [0; 2]; drop(fp.read(&mut length_buffer)); let length = u16::from_le_bytes(length_buffer) + 1; @@ -357,7 +387,12 @@ impl Silence { drop(fp.read(&mut frequency_divisor_buffer)); let sample_rate: u32 = 1000000u32 / (256u32 - frequency_divisor_buffer[0] as u32); - Self::new(length, sample_rate) + Self { + info: Some(BlockInfo { start_address, end_address }), + block_type: BlockType::Silence, + length, + sample_rate, + } } } @@ -379,6 +414,7 @@ impl Block for Silence { result } + fn get_info(&self) -> &Option { &self.info } } impl fmt::Debug for Silence { @@ -393,6 +429,7 @@ impl fmt::Debug for Silence { // Marker pub struct Marker { + info: Option, block_type: BlockType, value: u16, } @@ -400,17 +437,21 @@ pub struct Marker { impl Marker { pub fn new(value: u16) -> Self { Self { + info: None, block_type: BlockType::Marker, - value + value, } } - - pub fn from_stream(fp: &mut File, _end_address: u32) -> Self { + pub fn from_stream(fp: &mut File, start_address: u32, end_address: u32) -> Self { let mut value_buffer: [u8; 2] = [0; 2]; drop(fp.read(&mut value_buffer)); let value = u16::from_le_bytes(value_buffer); - Self::new(value) + Self { + info: Some(BlockInfo { start_address, end_address }), + block_type: BlockType::Marker, + value, + } } } @@ -430,6 +471,7 @@ impl Block for Marker { result } + fn get_info(&self) -> &Option { &self.info } } impl fmt::Debug for Marker { @@ -443,24 +485,23 @@ impl fmt::Debug for Marker { // Text pub struct Text { - block_type: BlockType, + pub info: Option, + pub block_type: BlockType, pub data: Vec, } impl Text { - pub fn new(data: Vec) -> Self { - Self { - block_type: BlockType::Text, - data, - } - } - - pub fn from_stream(fp: &mut File, end_address: u32) -> Self { + pub fn new(data: Vec) -> 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.seek(SeekFrom::Current(0)).unwrap() as u32; let mut data: Vec = vec![0; (end_address - address) as usize]; drop(fp.read(&mut data)); - Self::new(data) + Self { + info: Some(BlockInfo { start_address, end_address }), + block_type: BlockType::Text, + data, + } } } @@ -479,6 +520,7 @@ impl Block for Text { result } + fn get_info(&self) -> &Option { &self.info } } impl fmt::Debug for Text { @@ -492,24 +534,29 @@ impl fmt::Debug for Text { // RepeatStart pub struct RepeatStart { + info: Option, block_type: BlockType, - pub count: u16 + count: u16, } impl RepeatStart { pub fn new(count: u16) -> Self { Self { + info: None, block_type: BlockType::RepeatStart, - count + count, } } - - pub fn from_stream(fp: &mut File, _end_address: u32) -> Self { + pub fn from_stream(fp: &mut File, start_address: u32, end_address: u32) -> Self { let mut count_buffer: [u8; 2] = [0; 2]; drop(fp.read(&mut count_buffer)); let count = u16::from_le_bytes(count_buffer) + 1; - Self::new(count) + Self { + info: Some(BlockInfo { start_address, end_address }), + block_type: BlockType::RepeatStart, + count, + } } } @@ -529,6 +576,7 @@ impl Block for RepeatStart { result } + fn get_info(&self) -> &Option { &self.info } } impl fmt::Debug for RepeatStart { @@ -542,16 +590,17 @@ impl fmt::Debug for RepeatStart { // RepeatEnd pub struct RepeatEnd { - block_type: BlockType + info: Option, + block_type: BlockType, } impl RepeatEnd { - pub fn new() -> Self { - Self { block_type: BlockType::RepeatEnd } - } - - pub fn from_stream(_fp: &mut File, _end_address: u32) -> Self { - Self::new() + 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 { start_address, end_address }), + block_type: BlockType::RepeatEnd, + } } } @@ -559,6 +608,7 @@ impl Block for RepeatEnd { fn to_bytes(&self) -> Vec { vec![self.block_type as u8] } + fn get_info(&self) -> &Option { &self.info } } impl fmt::Debug for RepeatEnd {