RIFF cleanup

Signed-off-by: Serial <69764315+Serial-ATA@users.noreply.github.com>
This commit is contained in:
Serial 2021-07-06 12:17:08 -04:00
parent 2a3e54ba25
commit d403b11783

View file

@ -6,26 +6,28 @@ use std::fs::File;
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
// Used to determine the RIFF metadata format
pub const LIST_ID: &[u8; 4] = b"LIST";
pub const LIST_ID: &[u8] = b"LIST";
// FourCC
// Standard
pub const IART: [u8; 4] = [73, 65, 82, 84];
pub const ICMT: [u8; 4] = [73, 67, 77, 84];
pub const ICRD: [u8; 4] = [73, 67, 82, 68];
pub const INAM: [u8; 4] = [73, 78, 65, 77];
pub const IPRD: [u8; 4] = [73, 80, 82, 68]; // Represents album title
pub const IART: &[u8] = &[73, 65, 82, 84];
pub const ICMT: &[u8] = &[73, 67, 77, 84];
pub const ICRD: &[u8] = &[73, 67, 82, 68];
pub const INAM: &[u8] = &[73, 78, 65, 77];
pub const IPRD: &[u8] = &[73, 80, 82, 68]; // Represents album title
// Non-standard
pub const ITRK: [u8; 4] = [73, 84, 82, 75]; // Can represent track number
pub const IPRT: [u8; 4] = [73, 80, 82, 84]; // Can also represent track number
pub const IFRM: [u8; 4] = [73, 70, 82, 77]; // Can represent total tracks
pub const ITRK: &[u8] = &[73, 84, 82, 75]; // Can represent track number
pub const IPRT: &[u8] = &[73, 80, 82, 84]; // Can also represent track number
pub const IFRM: &[u8] = &[73, 70, 82, 77]; // Can represent total tracks
// Very non-standard
pub const ALBU: [u8; 4] = [65, 76, 66, 85]; // Can album artist OR album title
pub const TRAC: [u8; 4] = [84, 82, 65, 67]; // Can represent track number OR total tracks
pub const DISC: [u8; 4] = [68, 73, 83, 67]; // Can represent disc number OR total discs
pub const ALBU: &[u8] = &[65, 76, 66, 85]; // Can album artist OR album title
pub const TRAC: &[u8] = &[84, 82, 65, 67]; // Can represent track number OR total tracks
pub const DISC: &[u8] = &[68, 73, 83, 67]; // Can represent disc number OR total discs
pub const NULL_CHAR: char = '\0';
pub(crate) fn read_from<T>(data: &mut T) -> Result<Option<HashMap<String, String>>>
where
@ -37,20 +39,19 @@ where
find_info_list(data)?;
let mut info_list_size = [0; 4];
data.read_exact(&mut info_list_size)?;
let info_list_size = data.read_u32::<LittleEndian>()?;
let mut info_list = vec![0; u32::from_le_bytes(info_list_size) as usize];
let mut info_list = vec![0; info_list_size as usize];
data.read_exact(&mut info_list)?;
info_list.drain(0..4); // Get rid of the chunk ID
let mut cursor = Cursor::new(&*info_list);
cursor.seek(SeekFrom::Start(4))?; // Skip the chunk ID
let chunk_len = info_list.len();
let mut metadata: HashMap<String, String> = HashMap::with_capacity(chunk_len as usize);
let mut metadata: HashMap<String, String> = HashMap::new();
let mut reading = true;
#[allow(clippy::cast_lossless)]
while reading {
if let (Ok(fourcc), Ok(size)) = (
cursor.read_u32::<LittleEndian>(),
@ -61,25 +62,21 @@ where
let mut buf = vec![0; size as usize];
cursor.read_exact(&mut buf)?;
// Just skip any values that can't be converted
match std::string::String::from_utf8(buf) {
Ok(val) => {
let _ =
metadata.insert(key, val.trim_matches(char::from(0)).to_string());
let _ = metadata.insert(key, val.trim_matches(NULL_CHAR).to_string());
},
Err(_) => {
return Err(LoftyError::InvalidData(
"RIFF file contains non UTF-8 strings",
))
},
Err(_) => continue,
}
},
#[allow(clippy::cast_lossless)]
None => cursor.set_position(cursor.position() + size as u64),
}
// Skip null byte
if size as usize % 2 != 0 {
cursor.set_position(cursor.position() + 1)
}
if cursor.position() >= cursor.get_ref().len() as u64 {
if cursor.position() >= info_list_size as u64 {
reading = false
}
} else {
@ -98,7 +95,7 @@ where
let mut chunk_name = [0; 4];
data.read_exact(&mut chunk_name)?;
if &chunk_name == LIST_ID {
if chunk_name == LIST_ID {
data.seek(SeekFrom::Current(4))?;
let mut list_type = [0; 4];
@ -133,23 +130,19 @@ where
fn create_key(fourcc: &[u8]) -> Option<String> {
match fourcc {
fcc if fcc == IART => Some("Artist".to_string()),
fcc if fcc == ICMT => Some("Comment".to_string()),
fcc if fcc == ICRD => Some("Date".to_string()),
fcc if fcc == INAM => Some("Title".to_string()),
fcc if fcc == IPRD => Some("Album".to_string()),
// Non-standard
fcc if fcc == ITRK || fcc == IPRT => Some("TrackNumber".to_string()),
fcc if fcc == IFRM => Some("TrackTotal".to_string()),
fcc if fcc == ALBU => Some("Album".to_string()),
fcc if fcc == TRAC => Some("TrackNumber".to_string()),
fcc if fcc == DISC => Some("DiscNumber".to_string()),
IART => Some("Artist".to_string()),
ICMT => Some("Comment".to_string()),
ICRD => Some("Date".to_string()),
INAM => Some("Title".to_string()),
IPRD | ALBU => Some("Album".to_string()),
ITRK | IPRT | TRAC => Some("TrackNumber".to_string()),
IFRM => Some("TrackTotal".to_string()),
DISC => Some("DiscNumber".to_string()),
_ => None,
}
}
pub fn key_to_fourcc(key: &str) -> Option<[u8; 4]> {
pub fn key_to_fourcc(key: &str) -> Option<&[u8]> {
match key {
"Artist" => Some(IART),
"Comment" => Some(ICMT),
@ -186,7 +179,13 @@ pub(crate) fn write_to(data: &mut File, metadata: HashMap<String, String>) -> Re
}
}
let size = ((packet.len() - 4) as u32).to_le_bytes();
let packet_size = packet.len() - 4;
if packet_size > u32::MAX as usize {
return Err(LoftyError::TooMuchData);
}
let size = (packet_size as u32).to_le_bytes();
#[allow(clippy::needless_range_loop)]
for i in 0..4 {