mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2024-12-13 22:22:31 +00:00
Cleanup
This commit is contained in:
parent
7aa96ad0bb
commit
9c599f2aa9
2 changed files with 111 additions and 77 deletions
|
@ -14,15 +14,19 @@ const PCM: u16 = 0x0001;
|
||||||
const IEEE_FLOAT: u16 = 0x0003;
|
const IEEE_FLOAT: u16 = 0x0003;
|
||||||
const EXTENSIBLE: u16 = 0xfffe;
|
const EXTENSIBLE: u16 = 0xfffe;
|
||||||
|
|
||||||
pub(in crate::logic::iff) fn verify_riff<T>(data: &mut T) -> Result<()>
|
pub(in crate::logic::iff) fn verify_wav<T>(data: &mut T) -> Result<()>
|
||||||
where
|
where
|
||||||
T: Read + Seek,
|
T: Read + Seek,
|
||||||
{
|
{
|
||||||
let mut id = [0; 4];
|
let mut id = [0; 12];
|
||||||
data.read_exact(&mut id)?;
|
data.read_exact(&mut id)?;
|
||||||
|
|
||||||
if &id != b"RIFF" {
|
if &id[..4] != b"RIFF" {
|
||||||
return Err(LoftyError::Wav("RIFF file doesn't contain a RIFF chunk"));
|
return Err(LoftyError::Wav("WAV file doesn't contain a RIFF chunk"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if &id[8..] != b"WAVE" {
|
||||||
|
return Err(LoftyError::Wav("Found RIFF file, format is not WAVE"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -100,13 +104,11 @@ fn read_properties(fmt: &mut &[u8], total_samples: u32, stream_len: u32) -> Resu
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::logic) fn read_from<T>(data: &mut T) -> Result<WavFile>
|
pub(in crate::logic) fn read_from<R>(data: &mut R) -> Result<WavFile>
|
||||||
where
|
where
|
||||||
T: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
verify_riff(data)?;
|
verify_wav(data)?;
|
||||||
|
|
||||||
data.seek(SeekFrom::Current(8))?;
|
|
||||||
|
|
||||||
let mut stream_len = 0_u32;
|
let mut stream_len = 0_u32;
|
||||||
let mut total_samples = 0_u32;
|
let mut total_samples = 0_u32;
|
||||||
|
@ -154,31 +156,7 @@ where
|
||||||
|
|
||||||
if &list_type == b"INFO" {
|
if &list_type == b"INFO" {
|
||||||
let end = data.seek(SeekFrom::Current(0))? + u64::from(size - 4);
|
let end = data.seek(SeekFrom::Current(0))? + u64::from(size - 4);
|
||||||
|
parse_riff_info(data, end, &mut riff_info)?;
|
||||||
while data.seek(SeekFrom::Current(0))? != end {
|
|
||||||
let mut key = [0; 4];
|
|
||||||
data.read_exact(&mut key)?;
|
|
||||||
|
|
||||||
let key_str = std::str::from_utf8(&key)
|
|
||||||
.map_err(|_| LoftyError::Wav("Non UTF-8 key found in RIFF INFO"))?;
|
|
||||||
|
|
||||||
let item_key = ItemKey::from_key(&TagType::RiffInfo, key_str)
|
|
||||||
.unwrap_or_else(|| ItemKey::Unknown(key_str.to_string()));
|
|
||||||
|
|
||||||
let size = data.read_u32::<LittleEndian>()?;
|
|
||||||
|
|
||||||
let mut buf = vec![0; size as usize];
|
|
||||||
data.read_exact(&mut buf)?;
|
|
||||||
|
|
||||||
let val = String::from_utf8(buf)?;
|
|
||||||
|
|
||||||
let item = TagItem::new(
|
|
||||||
item_key,
|
|
||||||
ItemValue::Text(val.trim_matches('\0').to_string()),
|
|
||||||
);
|
|
||||||
|
|
||||||
riff_info.insert_item(item);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
data.seek(SeekFrom::Current(i64::from(size)))?;
|
data.seek(SeekFrom::Current(i64::from(size)))?;
|
||||||
}
|
}
|
||||||
|
@ -220,3 +198,38 @@ where
|
||||||
id3v2: id3,
|
id3v2: id3,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_riff_info<R>(data: &mut R, end: u64, tag: &mut Tag) -> Result<()>
|
||||||
|
where
|
||||||
|
R: Read + Seek,
|
||||||
|
{
|
||||||
|
while data.seek(SeekFrom::Current(0))? != end {
|
||||||
|
let mut key = [0; 4];
|
||||||
|
data.read_exact(&mut key)?;
|
||||||
|
|
||||||
|
let key_str = std::str::from_utf8(&key)
|
||||||
|
.map_err(|_| LoftyError::Wav("Non UTF-8 key found in RIFF INFO"))?;
|
||||||
|
|
||||||
|
if !key_str.is_ascii() {
|
||||||
|
return Err(LoftyError::Wav("Non ascii key found in RIFF INFO"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let item_key = ItemKey::from_key(&TagType::RiffInfo, key_str)
|
||||||
|
.unwrap_or_else(|| ItemKey::Unknown(key_str.to_string()));
|
||||||
|
|
||||||
|
let size = data.read_u32::<LittleEndian>()?;
|
||||||
|
|
||||||
|
let mut value = vec![0; size as usize];
|
||||||
|
data.read_exact(&mut value)?;
|
||||||
|
|
||||||
|
let value_str = std::str::from_utf8(&value)
|
||||||
|
.map_err(|_| LoftyError::Wav("Non UTF-8 value found in RIFF INFO"))?;
|
||||||
|
|
||||||
|
tag.insert_item_unchecked(TagItem::new(
|
||||||
|
item_key,
|
||||||
|
ItemValue::Text(value_str.trim_matches('\0').to_string()),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -1,37 +1,41 @@
|
||||||
use super::read::verify_riff;
|
use super::read::verify_wav;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
use crate::types::tag::{ItemValue, Tag, TagType};
|
use crate::types::tag::{ItemValue, Tag, TagType};
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
|
||||||
fn find_info_list<T>(data: &mut T) -> Result<()>
|
fn find_info_list<T>(data: &mut T) -> Result<bool>
|
||||||
where
|
where
|
||||||
T: Read + Seek,
|
T: Read + Seek,
|
||||||
{
|
{
|
||||||
loop {
|
let mut fourcc = [0; 4];
|
||||||
let mut chunk_name = [0; 4];
|
|
||||||
data.read_exact(&mut chunk_name)?;
|
|
||||||
|
|
||||||
if &chunk_name == b"LIST" {
|
let mut found_info = false;
|
||||||
data.seek(SeekFrom::Current(4))?;
|
|
||||||
|
|
||||||
|
while let (Ok(()), Ok(size)) = (
|
||||||
|
data.read_exact(&mut fourcc),
|
||||||
|
data.read_u32::<LittleEndian>(),
|
||||||
|
) {
|
||||||
|
if &fourcc == b"LIST" {
|
||||||
let mut list_type = [0; 4];
|
let mut list_type = [0; 4];
|
||||||
data.read_exact(&mut list_type)?;
|
data.read_exact(&mut list_type)?;
|
||||||
|
|
||||||
if &list_type == b"INFO" {
|
if &list_type == b"INFO" {
|
||||||
data.seek(SeekFrom::Current(-8))?;
|
data.seek(SeekFrom::Current(-8))?;
|
||||||
return Ok(());
|
found_info = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.seek(SeekFrom::Current(-8))?;
|
data.seek(SeekFrom::Current(-8))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = data.read_u32::<LittleEndian>()?;
|
|
||||||
data.seek(SeekFrom::Current(i64::from(size)))?;
|
data.seek(SeekFrom::Current(i64::from(size)))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(found_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: ID3v2
|
// TODO: ID3v2
|
||||||
|
@ -40,12 +44,52 @@ pub(crate) fn write_to(data: &mut File, tag: &Tag) -> Result<()> {
|
||||||
return Err(LoftyError::UnsupportedTag);
|
return Err(LoftyError::UnsupportedTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_riff(data)?;
|
verify_wav(data)?;
|
||||||
|
|
||||||
let mut packet = Vec::new();
|
let mut riff_info_bytes = Vec::new();
|
||||||
|
create_riff_info(tag, &mut riff_info_bytes)?;
|
||||||
|
|
||||||
packet.extend(b"LIST".iter());
|
if find_info_list(data)? {
|
||||||
packet.extend(b"INFO".iter());
|
let info_list_size = data.read_u32::<LittleEndian>()? as usize;
|
||||||
|
data.seek(SeekFrom::Current(-8))?;
|
||||||
|
|
||||||
|
let info_list_start = data.seek(SeekFrom::Current(0))? as usize;
|
||||||
|
let info_list_end = info_list_start + 8 + info_list_size;
|
||||||
|
|
||||||
|
data.seek(SeekFrom::Start(0))?;
|
||||||
|
|
||||||
|
let mut file_bytes = Vec::new();
|
||||||
|
data.read_to_end(&mut file_bytes)?;
|
||||||
|
|
||||||
|
let _ = file_bytes.splice(info_list_start..info_list_end, riff_info_bytes);
|
||||||
|
|
||||||
|
let total_size = (file_bytes.len() - 8) as u32;
|
||||||
|
let _ = file_bytes.splice(4..8, total_size.to_le_bytes());
|
||||||
|
|
||||||
|
data.seek(SeekFrom::Start(0))?;
|
||||||
|
data.set_len(0)?;
|
||||||
|
data.write_all(&*file_bytes)?;
|
||||||
|
} else {
|
||||||
|
data.seek(SeekFrom::End(0))?;
|
||||||
|
|
||||||
|
data.write_all(&riff_info_bytes)?;
|
||||||
|
|
||||||
|
let len = (data.seek(SeekFrom::Current(0))? - 8) as u32;
|
||||||
|
|
||||||
|
data.seek(SeekFrom::Start(4))?;
|
||||||
|
data.write_u32::<LittleEndian>(len)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_riff_info(tag: &Tag, bytes: &mut Vec<u8>) -> Result<()> {
|
||||||
|
if tag.item_count() == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes.extend(b"LIST".iter());
|
||||||
|
bytes.extend(b"INFO".iter());
|
||||||
|
|
||||||
for item in tag.items() {
|
for item in tag.items() {
|
||||||
if let Some(key) = item.key().map_key(&TagType::RiffInfo) {
|
if let Some(key) = item.key().map_key(&TagType::RiffInfo) {
|
||||||
|
@ -66,16 +110,16 @@ pub(crate) fn write_to(data: &mut File, tag: &Tag) -> Result<()> {
|
||||||
((len + 1) as u32, &[0, 0])
|
((len + 1) as u32, &[0, 0])
|
||||||
};
|
};
|
||||||
|
|
||||||
packet.extend(key.as_bytes().iter());
|
bytes.extend(key.as_bytes().iter());
|
||||||
packet.extend(size.to_le_bytes().iter());
|
bytes.extend(size.to_le_bytes().iter());
|
||||||
packet.extend(val_b.iter());
|
bytes.extend(val_b.iter());
|
||||||
packet.extend(terminator.iter());
|
bytes.extend(terminator.iter());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let packet_size = packet.len() - 4;
|
let packet_size = bytes.len() - 4;
|
||||||
|
|
||||||
if packet_size > u32::MAX as usize {
|
if packet_size > u32::MAX as usize {
|
||||||
return Err(LoftyError::TooMuchData);
|
return Err(LoftyError::TooMuchData);
|
||||||
|
@ -85,31 +129,8 @@ pub(crate) fn write_to(data: &mut File, tag: &Tag) -> Result<()> {
|
||||||
|
|
||||||
#[allow(clippy::needless_range_loop)]
|
#[allow(clippy::needless_range_loop)]
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
packet.insert(i + 4, size[i]);
|
bytes.insert(i + 4, size[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
data.seek(SeekFrom::Current(8))?;
|
|
||||||
|
|
||||||
find_info_list(data)?;
|
|
||||||
|
|
||||||
let info_list_size = data.read_u32::<LittleEndian>()? as usize;
|
|
||||||
data.seek(SeekFrom::Current(-8))?;
|
|
||||||
|
|
||||||
let info_list_start = data.seek(SeekFrom::Current(0))? as usize;
|
|
||||||
let info_list_end = info_list_start + 8 + info_list_size;
|
|
||||||
|
|
||||||
data.seek(SeekFrom::Start(0))?;
|
|
||||||
let mut file_bytes = Vec::new();
|
|
||||||
data.read_to_end(&mut file_bytes)?;
|
|
||||||
|
|
||||||
let _ = file_bytes.splice(info_list_start..info_list_end, packet);
|
|
||||||
|
|
||||||
let total_size = (file_bytes.len() - 8) as u32;
|
|
||||||
let _ = file_bytes.splice(4..8, total_size.to_le_bytes().to_vec());
|
|
||||||
|
|
||||||
data.seek(SeekFrom::Start(0))?;
|
|
||||||
data.set_len(0)?;
|
|
||||||
data.write_all(&*file_bytes)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue