Cleanups
This commit is contained in:
parent
0a0f5f5ed4
commit
ad50081574
531
src/voc.rs
531
src/voc.rs
|
@ -1,32 +1,11 @@
|
||||||
#![allow(clippy::new_without_default)]
|
#![allow(clippy::new_without_default)]
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Seek, Write};
|
use std::io::{Read, Seek, Write};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
use crate::voc::blocks::*;
|
||||||
pub enum Codec {
|
|
||||||
Pcm8BitUnsigned,
|
|
||||||
Adpcm4to8,
|
|
||||||
Adpcm3to8,
|
|
||||||
Adpcm2to8,
|
|
||||||
Pcm16BitSigned,
|
|
||||||
Alaw,
|
|
||||||
Ulaw,
|
|
||||||
Adpcm4to16,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
mod blocks;
|
||||||
pub enum BlockType {
|
|
||||||
Terminator,
|
|
||||||
SoundData,
|
|
||||||
SoundDataContinuation,
|
|
||||||
Silence,
|
|
||||||
Marker,
|
|
||||||
Text,
|
|
||||||
RepeatStart,
|
|
||||||
RepeatEnd,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct VocFile {
|
pub struct VocFile {
|
||||||
|
@ -40,11 +19,11 @@ impl VocFile {
|
||||||
const SIGNATURE2: [u8; 3] = [0x1A, 0x1A, 0x0];
|
const SIGNATURE2: [u8; 3] = [0x1A, 0x1A, 0x0];
|
||||||
|
|
||||||
pub fn from_file(file_name: &str) -> Self {
|
pub fn from_file(file_name: &str) -> Self {
|
||||||
let mut fp = File::open(file_name).unwrap();
|
let mut file = File::open(file_name).unwrap();
|
||||||
|
|
||||||
// Signature - Creative Voice File
|
// Signature - Creative Voice File
|
||||||
let mut signature1_buffer: [u8; 19] = [0; 19];
|
let mut signature1_buffer: [u8; 19] = [0; 19];
|
||||||
drop(fp.read(&mut signature1_buffer));
|
drop(file.read(&mut signature1_buffer));
|
||||||
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);
|
||||||
|
@ -52,31 +31,31 @@ impl VocFile {
|
||||||
|
|
||||||
// Signature - 1A 1A 00
|
// Signature - 1A 1A 00
|
||||||
let mut signature2_buffer: [u8; 3] = [0; 3];
|
let mut signature2_buffer: [u8; 3] = [0; 3];
|
||||||
drop(fp.read(&mut signature2_buffer));
|
drop(file.read(&mut signature2_buffer));
|
||||||
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
|
||||||
let mut version_buffer: [u8; 2] = [0; 2];
|
let mut version_buffer: [u8; 2] = [0; 2];
|
||||||
drop(fp.read(&mut version_buffer));
|
drop(file.read(&mut version_buffer));
|
||||||
let version_int = i16::from_le_bytes(version_buffer);
|
let version_int = i16::from_le_bytes(version_buffer);
|
||||||
let version = (version_buffer[1], version_buffer[0]);
|
let version = (version_buffer[1], version_buffer[0]);
|
||||||
|
|
||||||
// Version checksum
|
// Version checksum
|
||||||
let mut checksum_buffer: [u8; 2] = [0; 2];
|
let mut checksum_buffer: [u8; 2] = [0; 2];
|
||||||
drop(fp.read(&mut checksum_buffer));
|
drop(file.read(&mut checksum_buffer));
|
||||||
let checksum = (!version_int + 0x1234).to_le_bytes();
|
let checksum = (!version_int + 0x1234).to_le_bytes();
|
||||||
let checksum_result = checksum_buffer == checksum;
|
let checksum_result = checksum_buffer == checksum;
|
||||||
|
|
||||||
let mut voc = 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 = fp.stream_position().unwrap() as u32;
|
let block_start_address = file.stream_position().unwrap() as u32;
|
||||||
|
|
||||||
// Block Type
|
// Block Type
|
||||||
let mut block_type_buffer: [u8; 1] = [0];
|
let mut block_type_buffer: [u8; 1] = [0];
|
||||||
drop(fp.read(&mut block_type_buffer));
|
drop(file.read(&mut block_type_buffer));
|
||||||
let block_type = match block_type_buffer[0] {
|
let block_type = match block_type_buffer[0] {
|
||||||
0 => BlockType::Terminator,
|
0 => BlockType::Terminator,
|
||||||
1 => BlockType::SoundData,
|
1 => BlockType::SoundData,
|
||||||
|
@ -94,63 +73,63 @@ impl VocFile {
|
||||||
// Terminator and RepeatEnd dont have size in header so block_size is 0
|
// Terminator and RepeatEnd dont have size in header so block_size is 0
|
||||||
if block_type != BlockType::Terminator || block_type != BlockType::RepeatEnd {
|
if block_type != BlockType::Terminator || block_type != BlockType::RepeatEnd {
|
||||||
let mut block_size_buffer: [u8; 3] = [0; 3];
|
let mut block_size_buffer: [u8; 3] = [0; 3];
|
||||||
drop(fp.read(&mut block_size_buffer));
|
drop(file.read(&mut block_size_buffer));
|
||||||
block_size = u32::from_le_bytes(
|
block_size = u32::from_le_bytes(
|
||||||
[block_size_buffer[0], block_size_buffer[1], block_size_buffer[2], 0]
|
[block_size_buffer[0], block_size_buffer[1], block_size_buffer[2], 0]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let current_address = fp.stream_position().unwrap() as u32;
|
let current_address = file.stream_position().unwrap() as u32;
|
||||||
let block_end_address = current_address + block_size;
|
let block_end_address = current_address + block_size;
|
||||||
|
|
||||||
|
|
||||||
match block_type {
|
match block_type {
|
||||||
BlockType::Terminator => {
|
BlockType::Terminator => {
|
||||||
let block = Terminator::from_stream(&mut fp, block_start_address, block_end_address);
|
let block = Terminator::from_stream(&mut file, block_start_address, block_end_address);
|
||||||
voc.blocks.push(Box::new(block));
|
voc_file.blocks.push(Box::new(block));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
BlockType::SoundData => {
|
BlockType::SoundData => {
|
||||||
let block = SoundData::from_stream(&mut fp, block_start_address, block_end_address);
|
let block = SoundData::from_stream(&mut file, block_start_address, block_end_address);
|
||||||
voc.blocks.push(Box::new(block));
|
voc_file.blocks.push(Box::new(block));
|
||||||
}
|
}
|
||||||
BlockType::SoundDataContinuation => {
|
BlockType::SoundDataContinuation => {
|
||||||
let block = SoundDataContinuation::from_stream(&mut fp, block_start_address, block_end_address);
|
let block = SoundDataContinuation::from_stream(&mut file, block_start_address, block_end_address);
|
||||||
voc.blocks.push(Box::new(block));
|
voc_file.blocks.push(Box::new(block));
|
||||||
}
|
}
|
||||||
BlockType::Silence => {
|
BlockType::Silence => {
|
||||||
let block = Silence::from_stream(&mut fp, block_start_address, block_end_address);
|
let block = Silence::from_stream(&mut file, block_start_address, block_end_address);
|
||||||
voc.blocks.push(Box::new(block));
|
voc_file.blocks.push(Box::new(block));
|
||||||
}
|
}
|
||||||
BlockType::Marker => {
|
BlockType::Marker => {
|
||||||
let block = Marker::from_stream(&mut fp, block_start_address, block_end_address);
|
let block = Marker::from_stream(&mut file, block_start_address, block_end_address);
|
||||||
voc.blocks.push(Box::new(block));
|
voc_file.blocks.push(Box::new(block));
|
||||||
}
|
}
|
||||||
BlockType::Text => {
|
BlockType::Text => {
|
||||||
let block = Text::from_stream(&mut fp, block_start_address, block_end_address);
|
let block = Text::from_stream(&mut file, block_start_address, block_end_address);
|
||||||
voc.blocks.push(Box::new(block));
|
voc_file.blocks.push(Box::new(block));
|
||||||
}
|
}
|
||||||
BlockType::RepeatStart => {
|
BlockType::RepeatStart => {
|
||||||
let block = RepeatStart::from_stream(&mut fp, block_start_address, block_end_address);
|
let block = RepeatStart::from_stream(&mut file, block_start_address, block_end_address);
|
||||||
voc.blocks.push(Box::new(block));
|
voc_file.blocks.push(Box::new(block));
|
||||||
}
|
}
|
||||||
BlockType::RepeatEnd => {
|
BlockType::RepeatEnd => {
|
||||||
let block = RepeatEnd::from_stream(&mut fp, block_start_address, block_end_address);
|
let block = RepeatEnd::from_stream(&mut file, block_start_address, block_end_address);
|
||||||
voc.blocks.push(Box::new(block));
|
voc_file.blocks.push(Box::new(block));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
voc
|
voc_file
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_bytes(&self) -> Vec<u8> {
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
let mut result: Vec<u8> = Vec::new();
|
let mut result: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
// Signature1
|
// Signature1
|
||||||
let signature = "Creative Voice File".as_bytes();
|
result.extend_from_slice(Self::SIGNATURE1.as_bytes());
|
||||||
result.extend_from_slice(signature);
|
|
||||||
|
|
||||||
// Signature2
|
// Signature2
|
||||||
result.extend_from_slice(&[0x1A, 0x1A, 0x00]);
|
result.extend_from_slice(&Self::SIGNATURE2);
|
||||||
|
|
||||||
// Version
|
// Version
|
||||||
result.extend_from_slice(&[self.version.1, self.version.0]);
|
result.extend_from_slice(&[self.version.1, self.version.0]);
|
||||||
|
@ -173,448 +152,4 @@ impl VocFile {
|
||||||
drop(fp.write(&self.to_bytes()));
|
drop(fp.write(&self.to_bytes()));
|
||||||
drop(fp.flush());
|
drop(fp.flush());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 { 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<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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SoundData
|
|
||||||
|
|
||||||
pub struct SoundData {
|
|
||||||
info: Option<BlockInfo>,
|
|
||||||
block_type: BlockType,
|
|
||||||
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,
|
|
||||||
data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
let mut codec_buffer: [u8; 1] = [0];
|
|
||||||
drop(fp.read(&mut codec_buffer));
|
|
||||||
let codec = match codec_buffer[0] {
|
|
||||||
0 => Codec::Pcm8BitUnsigned,
|
|
||||||
1 => Codec::Adpcm4to8,
|
|
||||||
2 => Codec::Adpcm3to8,
|
|
||||||
3 => Codec::Adpcm2to8,
|
|
||||||
4 => Codec::Pcm16BitSigned,
|
|
||||||
5 => Codec::Alaw,
|
|
||||||
6 => Codec::Ulaw,
|
|
||||||
7 => Codec::Adpcm4to16,
|
|
||||||
_ => panic!("Bad Sound format. Got {}", codec_buffer[0])
|
|
||||||
};
|
|
||||||
|
|
||||||
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 { start_address, end_address }),
|
|
||||||
block_type: BlockType::SoundData,
|
|
||||||
sample_rate,
|
|
||||||
codec,
|
|
||||||
data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Block for SoundData {
|
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
|
||||||
let size_bytes: [u8; 4] = (self.data.len() as u32 + 2).to_le_bytes();
|
|
||||||
let frequency_divisor: u8 = (256u32 - 1000000u32 / self.sample_rate) as u8;
|
|
||||||
|
|
||||||
let mut result: Vec<u8> = vec![
|
|
||||||
self.block_type as u8,
|
|
||||||
size_bytes[0],
|
|
||||||
size_bytes[1],
|
|
||||||
size_bytes[2],
|
|
||||||
frequency_divisor,
|
|
||||||
self.codec as u8,
|
|
||||||
];
|
|
||||||
|
|
||||||
result.extend_from_slice(&self.data);
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
fn get_info(&self) -> &Option<BlockInfo> { &self.info }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for SoundData {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("SoundData")
|
|
||||||
.field("size", &self.data.len())
|
|
||||||
.field("sample rate", &self.sample_rate)
|
|
||||||
.field("codec", &self.codec)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SoundDataContinuation
|
|
||||||
|
|
||||||
pub struct SoundDataContinuation {
|
|
||||||
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, 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 { start_address, end_address }),
|
|
||||||
block_type: BlockType::SoundDataContinuation,
|
|
||||||
data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Block for SoundDataContinuation {
|
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
|
||||||
let size_bytes: [u8; 4] = (self.data.len() as u32).to_le_bytes();
|
|
||||||
let mut result: Vec<u8> = vec![
|
|
||||||
self.block_type as u8,
|
|
||||||
size_bytes[0],
|
|
||||||
size_bytes[1],
|
|
||||||
size_bytes[2],
|
|
||||||
];
|
|
||||||
|
|
||||||
result.extend_from_slice(&self.data);
|
|
||||||
result
|
|
||||||
}
|
|
||||||
fn get_info(&self) -> &Option<BlockInfo> { &self.info }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for SoundDataContinuation {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("SoundDataContinuation")
|
|
||||||
.field("size", &self.data.len())
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Silence
|
|
||||||
|
|
||||||
pub struct Silence {
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
info: Some(BlockInfo { start_address, end_address }),
|
|
||||||
block_type: BlockType::Silence,
|
|
||||||
length,
|
|
||||||
sample_rate,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Block for Silence {
|
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
|
||||||
let size_bytes: [u8; 4] = 3u32.to_le_bytes();
|
|
||||||
let length_bytes: [u8; 2] = (self.length - 1).to_le_bytes();
|
|
||||||
let frequency_divisor: u8 = (256u32 - 1000000u32 / self.sample_rate) as u8;
|
|
||||||
|
|
||||||
let result: Vec<u8> = vec![
|
|
||||||
self.block_type as u8,
|
|
||||||
size_bytes[0],
|
|
||||||
size_bytes[1],
|
|
||||||
size_bytes[2],
|
|
||||||
length_bytes[0],
|
|
||||||
length_bytes[1],
|
|
||||||
frequency_divisor,
|
|
||||||
];
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
fn get_info(&self) -> &Option<BlockInfo> { &self.info }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Silence {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("Silence")
|
|
||||||
.field("length", &self.length)
|
|
||||||
.field("sample rate", &self.sample_rate)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marker
|
|
||||||
|
|
||||||
pub struct Marker {
|
|
||||||
info: Option<BlockInfo>,
|
|
||||||
block_type: BlockType,
|
|
||||||
value: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Marker {
|
|
||||||
pub fn new(value: u16) -> Self {
|
|
||||||
Self {
|
|
||||||
info: None,
|
|
||||||
block_type: BlockType::Marker,
|
|
||||||
value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
info: Some(BlockInfo { start_address, end_address }),
|
|
||||||
block_type: BlockType::Marker,
|
|
||||||
value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Block for Marker {
|
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
|
||||||
let size_bytes: [u8; 4] = 2u32.to_le_bytes();
|
|
||||||
let value_bytes: [u8; 2] = self.value.to_le_bytes();
|
|
||||||
|
|
||||||
let result: Vec<u8> = vec![
|
|
||||||
self.block_type as u8,
|
|
||||||
size_bytes[0],
|
|
||||||
size_bytes[1],
|
|
||||||
size_bytes[2],
|
|
||||||
value_bytes[0],
|
|
||||||
value_bytes[1],
|
|
||||||
];
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
fn get_info(&self) -> &Option<BlockInfo> { &self.info }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Marker {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("Marker")
|
|
||||||
.field("value", &self.value)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Text
|
|
||||||
|
|
||||||
pub struct Text {
|
|
||||||
pub info: Option<BlockInfo>,
|
|
||||||
pub block_type: BlockType,
|
|
||||||
pub data: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Text {
|
|
||||||
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 { start_address, end_address }),
|
|
||||||
block_type: BlockType::Text,
|
|
||||||
data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Block for Text {
|
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
|
||||||
let size_bytes: [u8; 4] = (self.data.len() as u32).to_le_bytes();
|
|
||||||
|
|
||||||
let mut result: Vec<u8> = vec![
|
|
||||||
self.block_type as u8,
|
|
||||||
size_bytes[0],
|
|
||||||
size_bytes[1],
|
|
||||||
size_bytes[2],
|
|
||||||
];
|
|
||||||
|
|
||||||
result.extend_from_slice(&self.data);
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
fn get_info(&self) -> &Option<BlockInfo> { &self.info }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Text {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("Text")
|
|
||||||
.field("size", &self.data.len())
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RepeatStart
|
|
||||||
|
|
||||||
pub struct RepeatStart {
|
|
||||||
info: Option<BlockInfo>,
|
|
||||||
block_type: BlockType,
|
|
||||||
count: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RepeatStart {
|
|
||||||
pub fn new(count: u16) -> Self {
|
|
||||||
Self {
|
|
||||||
info: None,
|
|
||||||
block_type: BlockType::RepeatStart,
|
|
||||||
count,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
info: Some(BlockInfo { start_address, end_address }),
|
|
||||||
block_type: BlockType::RepeatStart,
|
|
||||||
count,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Block for RepeatStart {
|
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
|
||||||
let size_bytes: [u8; 4] = 2u32.to_le_bytes();
|
|
||||||
let count_bytes: [u8; 2] = (self.count - 1).to_le_bytes();
|
|
||||||
|
|
||||||
let result: Vec<u8> = vec![
|
|
||||||
self.block_type as u8,
|
|
||||||
size_bytes[0],
|
|
||||||
size_bytes[1],
|
|
||||||
size_bytes[2],
|
|
||||||
count_bytes[0],
|
|
||||||
count_bytes[1],
|
|
||||||
];
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
fn get_info(&self) -> &Option<BlockInfo> { &self.info }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for RepeatStart {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("RepeatStart")
|
|
||||||
.field("count", &self.count)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RepeatEnd
|
|
||||||
|
|
||||||
pub struct RepeatEnd {
|
|
||||||
info: Option<BlockInfo>,
|
|
||||||
block_type: BlockType,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl 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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("RepeatEnd")
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,479 @@
|
||||||
|
use std::fmt;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum Codec {
|
||||||
|
Pcm8BitUnsigned,
|
||||||
|
Adpcm4to8,
|
||||||
|
Adpcm3to8,
|
||||||
|
Adpcm2to8,
|
||||||
|
Pcm16BitSigned,
|
||||||
|
Alaw,
|
||||||
|
Ulaw,
|
||||||
|
Adpcm4to16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||||
|
pub enum BlockType {
|
||||||
|
Terminator,
|
||||||
|
SoundData,
|
||||||
|
SoundDataContinuation,
|
||||||
|
Silence,
|
||||||
|
Marker,
|
||||||
|
Text,
|
||||||
|
RepeatStart,
|
||||||
|
RepeatEnd,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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 {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
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<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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SoundData
|
||||||
|
|
||||||
|
pub struct SoundData {
|
||||||
|
info: Option<BlockInfo>,
|
||||||
|
block_type: BlockType,
|
||||||
|
sample_rate: u32,
|
||||||
|
codec: Codec,
|
||||||
|
data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SoundData {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new(sample_rate: u32, codec: Codec, data: Vec<u8>) -> Self {
|
||||||
|
Self {
|
||||||
|
info: None,
|
||||||
|
block_type: BlockType::SoundData,
|
||||||
|
sample_rate,
|
||||||
|
codec,
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
let mut codec_buffer: [u8; 1] = [0];
|
||||||
|
drop(fp.read(&mut codec_buffer));
|
||||||
|
let codec = match codec_buffer[0] {
|
||||||
|
0 => Codec::Pcm8BitUnsigned,
|
||||||
|
1 => Codec::Adpcm4to8,
|
||||||
|
2 => Codec::Adpcm3to8,
|
||||||
|
3 => Codec::Adpcm2to8,
|
||||||
|
4 => Codec::Pcm16BitSigned,
|
||||||
|
5 => Codec::Alaw,
|
||||||
|
6 => Codec::Ulaw,
|
||||||
|
7 => Codec::Adpcm4to16,
|
||||||
|
_ => panic!("Bad Sound format. Got {}", codec_buffer[0])
|
||||||
|
};
|
||||||
|
|
||||||
|
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 { start_address, end_address }),
|
||||||
|
block_type: BlockType::SoundData,
|
||||||
|
sample_rate,
|
||||||
|
codec,
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Block for SoundData {
|
||||||
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let size_bytes: [u8; 4] = (self.data.len() as u32 + 2).to_le_bytes();
|
||||||
|
let frequency_divisor: u8 = (256u32 - 1000000u32 / self.sample_rate) as u8;
|
||||||
|
|
||||||
|
let mut result: Vec<u8> = vec![
|
||||||
|
self.block_type as u8,
|
||||||
|
size_bytes[0],
|
||||||
|
size_bytes[1],
|
||||||
|
size_bytes[2],
|
||||||
|
frequency_divisor,
|
||||||
|
self.codec as u8,
|
||||||
|
];
|
||||||
|
|
||||||
|
result.extend_from_slice(&self.data);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
fn get_info(&self) -> &Option<BlockInfo> { &self.info }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for SoundData {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("SoundData")
|
||||||
|
.field("size", &self.data.len())
|
||||||
|
.field("sample rate", &self.sample_rate)
|
||||||
|
.field("codec", &self.codec)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SoundDataContinuation
|
||||||
|
|
||||||
|
pub struct SoundDataContinuation {
|
||||||
|
info: Option<BlockInfo>,
|
||||||
|
block_type: BlockType,
|
||||||
|
data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SoundDataContinuation {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new(data: Vec<u8>) -> Self {
|
||||||
|
Self {
|
||||||
|
info: None,
|
||||||
|
block_type: BlockType::SoundDataContinuation,
|
||||||
|
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 { start_address, end_address }),
|
||||||
|
block_type: BlockType::SoundDataContinuation,
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Block for SoundDataContinuation {
|
||||||
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let size_bytes: [u8; 4] = (self.data.len() as u32).to_le_bytes();
|
||||||
|
let mut result: Vec<u8> = vec![
|
||||||
|
self.block_type as u8,
|
||||||
|
size_bytes[0],
|
||||||
|
size_bytes[1],
|
||||||
|
size_bytes[2],
|
||||||
|
];
|
||||||
|
|
||||||
|
result.extend_from_slice(&self.data);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
fn get_info(&self) -> &Option<BlockInfo> { &self.info }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for SoundDataContinuation {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("SoundDataContinuation")
|
||||||
|
.field("size", &self.data.len())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Silence
|
||||||
|
|
||||||
|
pub struct Silence {
|
||||||
|
info: Option<BlockInfo>,
|
||||||
|
block_type: BlockType,
|
||||||
|
length: u16,
|
||||||
|
sample_rate: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Silence {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new(length: u16, sample_rate: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
info: None,
|
||||||
|
block_type: BlockType::Silence,
|
||||||
|
length,
|
||||||
|
sample_rate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
info: Some(BlockInfo { start_address, end_address }),
|
||||||
|
block_type: BlockType::Silence,
|
||||||
|
length,
|
||||||
|
sample_rate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Block for Silence {
|
||||||
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let size_bytes: [u8; 4] = 3u32.to_le_bytes();
|
||||||
|
let length_bytes: [u8; 2] = (self.length - 1).to_le_bytes();
|
||||||
|
let frequency_divisor: u8 = (256u32 - 1000000u32 / self.sample_rate) as u8;
|
||||||
|
|
||||||
|
let result: Vec<u8> = vec![
|
||||||
|
self.block_type as u8,
|
||||||
|
size_bytes[0],
|
||||||
|
size_bytes[1],
|
||||||
|
size_bytes[2],
|
||||||
|
length_bytes[0],
|
||||||
|
length_bytes[1],
|
||||||
|
frequency_divisor,
|
||||||
|
];
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
fn get_info(&self) -> &Option<BlockInfo> { &self.info }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Silence {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Silence")
|
||||||
|
.field("length", &self.length)
|
||||||
|
.field("sample rate", &self.sample_rate)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marker
|
||||||
|
|
||||||
|
pub struct Marker {
|
||||||
|
info: Option<BlockInfo>,
|
||||||
|
block_type: BlockType,
|
||||||
|
value: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Marker {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new(value: u16) -> Self {
|
||||||
|
Self {
|
||||||
|
info: None,
|
||||||
|
block_type: BlockType::Marker,
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
info: Some(BlockInfo { start_address, end_address }),
|
||||||
|
block_type: BlockType::Marker,
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Block for Marker {
|
||||||
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let size_bytes: [u8; 4] = 2u32.to_le_bytes();
|
||||||
|
let value_bytes: [u8; 2] = self.value.to_le_bytes();
|
||||||
|
|
||||||
|
let result: Vec<u8> = vec![
|
||||||
|
self.block_type as u8,
|
||||||
|
size_bytes[0],
|
||||||
|
size_bytes[1],
|
||||||
|
size_bytes[2],
|
||||||
|
value_bytes[0],
|
||||||
|
value_bytes[1],
|
||||||
|
];
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
fn get_info(&self) -> &Option<BlockInfo> { &self.info }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Marker {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Marker")
|
||||||
|
.field("value", &self.value)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text
|
||||||
|
|
||||||
|
pub struct Text {
|
||||||
|
pub info: Option<BlockInfo>,
|
||||||
|
pub block_type: BlockType,
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Text {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
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 { start_address, end_address }),
|
||||||
|
block_type: BlockType::Text,
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Block for Text {
|
||||||
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let size_bytes: [u8; 4] = (self.data.len() as u32).to_le_bytes();
|
||||||
|
|
||||||
|
let mut result: Vec<u8> = vec![
|
||||||
|
self.block_type as u8,
|
||||||
|
size_bytes[0],
|
||||||
|
size_bytes[1],
|
||||||
|
size_bytes[2],
|
||||||
|
];
|
||||||
|
|
||||||
|
result.extend_from_slice(&self.data);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
fn get_info(&self) -> &Option<BlockInfo> { &self.info }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Text {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Text")
|
||||||
|
.field("size", &self.data.len())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepeatStart
|
||||||
|
|
||||||
|
pub struct RepeatStart {
|
||||||
|
info: Option<BlockInfo>,
|
||||||
|
block_type: BlockType,
|
||||||
|
count: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RepeatStart {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new(count: u16) -> Self {
|
||||||
|
Self {
|
||||||
|
info: None,
|
||||||
|
block_type: BlockType::RepeatStart,
|
||||||
|
count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
info: Some(BlockInfo { start_address, end_address }),
|
||||||
|
block_type: BlockType::RepeatStart,
|
||||||
|
count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Block for RepeatStart {
|
||||||
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let size_bytes: [u8; 4] = 2u32.to_le_bytes();
|
||||||
|
let count_bytes: [u8; 2] = (self.count - 1).to_le_bytes();
|
||||||
|
|
||||||
|
let result: Vec<u8> = vec![
|
||||||
|
self.block_type as u8,
|
||||||
|
size_bytes[0],
|
||||||
|
size_bytes[1],
|
||||||
|
size_bytes[2],
|
||||||
|
count_bytes[0],
|
||||||
|
count_bytes[1],
|
||||||
|
];
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
fn get_info(&self) -> &Option<BlockInfo> { &self.info }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for RepeatStart {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("RepeatStart")
|
||||||
|
.field("count", &self.count)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepeatEnd
|
||||||
|
|
||||||
|
pub struct RepeatEnd {
|
||||||
|
info: Option<BlockInfo>,
|
||||||
|
block_type: BlockType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RepeatEnd {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("RepeatEnd")
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue