Only read RIFF INFO LISTs instead of all LISTs

Signed-off-by: Serial <69764315+Serial-ATA@users.noreply.github.com>
This commit is contained in:
Serial 2021-05-15 20:57:31 -04:00
parent c285b36629
commit 028afaa9ee
2 changed files with 67 additions and 56 deletions

View file

@ -17,7 +17,7 @@ ape = {version = "0.3.0", optional = true}
# Wav # Wav
riff = {version = "1.0.1", optional = true} riff = {version = "1.0.1", optional = true}
# Mp3 # Mp3
id3 = {version = "0.6.3", optional = true} # De/Encoding id3 = {version = "0.6.4", optional = true} # De/Encoding
mp3-duration = {version = "0.1.10", optional = true} # Duration mp3-duration = {version = "0.1.10", optional = true} # Duration
# Ogg # Ogg
lewton = {version = "0.10.2", optional = true} # Decoding lewton = {version = "0.10.2", optional = true} # Decoding

View file

@ -11,72 +11,83 @@ where
{ {
let chunk = riff::Chunk::read(&mut data, 0)?; let chunk = riff::Chunk::read(&mut data, 0)?;
let mut list: Option<riff::Chunk> = None; let mut lists: Vec<riff::Chunk> = Vec::new();
for child in chunk.iter(&mut data) { for child in chunk.iter(&mut data) {
let chunk_id = child.id(); let chunk_id = child.id();
let value_upper = std::str::from_utf8(&chunk_id.value)?.to_uppercase();
let value_bytes = value_upper.as_bytes();
if value_bytes == LIST_ID { if &chunk_id.value == LIST_ID {
// TODO: actually check for the INFO id rather than any LIST lists.push(child)
list = Some(child);
break;
} }
} }
return if let Some(list) = list { return if lists.is_empty() {
let mut content = list.read_contents(&mut data)?; Err(Error::Wav(
"This file doesn't contain a LIST chunk".to_string(),
))
} else {
let mut info: Option<riff::Chunk> = None;
content.drain(0..4); // Get rid of the chunk ID for child in lists {
let mut cursor = Cursor::new(&*content); if &child.read_type(&mut data)?.value == b"INFO" {
info = Some(child);
let chunk_len = list.len(); break;
let mut metadata: HashMap<String, String> = HashMap::with_capacity(chunk_len as usize);
let mut reading = true;
while reading {
if let (Ok(fourcc), Ok(size)) = (
cursor.read_u32::<LittleEndian>(),
cursor.read_u32::<LittleEndian>(),
) {
match create_wav_key(&fourcc.to_le_bytes()) {
Some(key) => {
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());
},
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 {
reading = false
}
} else {
reading = false
} }
} }
Ok(Some(metadata)) if let Some(list) = info {
} else { let mut content = list.read_contents(&mut data)?;
Err(Error::Wav(
"This file doesn't contain an INFO chunk".to_string(), content.drain(0..4); // Get rid of the chunk ID
)) let mut cursor = Cursor::new(&*content);
let chunk_len = list.len();
let mut metadata: HashMap<String, String> = HashMap::with_capacity(chunk_len as usize);
let mut reading = true;
while reading {
if let (Ok(fourcc), Ok(size)) = (
cursor.read_u32::<LittleEndian>(),
cursor.read_u32::<LittleEndian>(),
) {
match create_wav_key(&fourcc.to_le_bytes()) {
Some(key) => {
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());
},
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 {
reading = false
}
} else {
reading = false
}
}
Ok(Some(metadata))
} else {
Err(Error::Wav(
"This file doesn't contain an INFO chunk".to_string(),
))
}
}; };
} }