* VocFile

- Dont panic on invalid version checksum
- Add new field to store checksum status

* BlockInfo
- New struct
- Contains start and end address of the block in the file
- Contains a get_size() function

* Block Trait
- Add a get_info() function that returns a BlockInfo

* Main
Prettify the *info* command.
Now shows the file version, checksum, and info about all the blocks.
This commit is contained in:
Pedro de Oliveira 2022-11-14 20:51:24 +00:00
parent 1dd3997587
commit a7273184f9
2 changed files with 155 additions and 76 deletions

View File

@ -14,18 +14,47 @@ fn main() {
.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();
match matches.subcommand() {
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!" }
);
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::<String>("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"),
};
}

View File

@ -31,6 +31,7 @@ pub enum BlockType {
#[derive(Debug)]
pub struct VocFile {
pub version: (u8, u8),
pub checksum: bool,
pub blocks: Vec<BlockT>,
}
@ -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<dyn Block>;
pub trait Block: fmt::Debug {
fn to_bytes(&self) -> Vec<u8>;
fn get_info(&self) -> &Option<BlockInfo>;
}
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<BlockInfo>,
block_type: BlockType,
}
impl Terminator {
pub fn new() -> Self {
Self { block_type: BlockType::Terminator }
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,
}
pub fn from_stream(_fp: &mut File, _end_address: u32) -> Self {
Self::new()
}
}
impl Block for Terminator {
fn to_bytes(&self) -> Vec<u8> {
vec![self.block_type as u8]
}
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 {
@ -211,15 +225,17 @@ impl fmt::Debug for Terminator {
// SoundData
pub struct SoundData {
info: Option<BlockInfo>,
block_type: BlockType,
pub sample_rate: u32,
pub codec: Codec,
pub data: Vec<u8>,
sample_rate: u32,
codec: Codec,
data: Vec<u8>,
}
impl SoundData {
pub fn new(sample_rate: u32, codec: Codec, data: Vec<u8>) -> 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<u8> = 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<BlockInfo> { &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<u8>,
info: Option<BlockInfo>,
block_type: BlockType,
data: Vec<u8>,
}
impl SoundDataContinuation {
pub fn new(data: Vec<u8>) -> 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<u8> = 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<BlockInfo> { &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<BlockInfo>,
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<BlockInfo> { &self.info }
}
impl fmt::Debug for Silence {
@ -393,6 +429,7 @@ impl fmt::Debug for Silence {
// Marker
pub struct Marker {
info: Option<BlockInfo>,
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<BlockInfo> { &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<BlockInfo>,
pub block_type: BlockType,
pub data: Vec<u8>,
}
impl Text {
pub fn new(data: Vec<u8>) -> Self {
Self {
block_type: BlockType::Text,
data,
}
}
pub fn from_stream(fp: &mut File, end_address: u32) -> Self {
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.seek(SeekFrom::Current(0)).unwrap() as u32;
let mut data: Vec<u8> = 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<BlockInfo> { &self.info }
}
impl fmt::Debug for Text {
@ -492,24 +534,29 @@ impl fmt::Debug for Text {
// RepeatStart
pub struct RepeatStart {
info: Option<BlockInfo>,
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<BlockInfo> { &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<BlockInfo>,
block_type: BlockType,
}
impl RepeatEnd {
pub fn new() -> Self {
Self { 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 { start_address, end_address }),
block_type: BlockType::RepeatEnd,
}
pub fn from_stream(_fp: &mut File, _end_address: u32) -> Self {
Self::new()
}
}
@ -559,6 +608,7 @@ impl Block for RepeatEnd {
fn to_bytes(&self) -> Vec<u8> {
vec![self.block_type as u8]
}
fn get_info(&self) -> &Option<BlockInfo> { &self.info }
}
impl fmt::Debug for RepeatEnd {