diff --git a/Cargo.toml b/Cargo.toml index 107cc764..5aa3e5fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.1" authors = ["Serial <69764315+Serial-ATA@users.noreply.github.com>", "Tianyi "] edition = "2018" license = "MIT OR Apache-2.0" -description = "Fork of https://github.com/TianyiShi2001/audiotags, adding support for more file types and (optionally) duration" +description = "Unified IO for different types of audio metadata" repository = "https://github.com/Serial-ATA/lofty-rs" keywords = ["tags", "audio", "metadata"] categories = ["accessibility", "multimedia::audio"] diff --git a/src/components/logic/write.rs b/src/components/logic/write.rs index 9292aa3f..b507cf90 100644 --- a/src/components/logic/write.rs +++ b/src/components/logic/write.rs @@ -53,26 +53,61 @@ where Ok(c.into_inner()) } +struct Page { + pub size_idx: usize, + pub content: Vec, + pub header_type: u8, + pub start: usize, + pub end: usize, +} + pub(crate) fn opus(mut data: T, packet: &[u8]) -> Result> where T: Read + Seek, { - let mut beginning_sig = [0; 4]; - data.read_exact(&mut beginning_sig)?; + fn read_page(mut data: V) -> Result + where + V: Read + Seek, + { + let mut sig = [0; 4]; + data.read_exact(&mut sig)?; - if &beginning_sig != b"OggS" { - return Err(Error::UnknownFormat); + if &sig != b"OggS" { + return Err(Error::UnknownFormat); + } + + let mut info = [0; 2]; + data.read_exact(&mut info)?; + + let header_type = info[1]; + + let mut page = [0; 21]; + data.read_exact(&mut page)?; + + let size_idx = data.seek(SeekFrom::Current(0))? as usize; + + let mut segment_table = vec![0; page[20] as usize]; + data.read_exact(&mut segment_table)?; + + let start = data.seek(SeekFrom::Current(0))? as usize; + + let mut content = vec![0; segment_table.iter().map(|&b| b as usize).sum()]; + data.read_exact(&mut content)?; + + let end = data.seek(SeekFrom::Current(0))? as usize; + + Ok(Page { + size_idx, + content, + header_type, + start, + end, + }) } - let mut first_page = [0; 23]; - data.read_exact(&mut first_page)?; - - let mut segment_table = vec![0; first_page[22] as usize]; - data.read_exact(&mut segment_table)?; - - let mut head = vec![0; segment_table.iter().map(|&b| b as usize).sum()]; - data.read_exact(&mut head)?; + let first_page = read_page(&mut data)?; + let head = first_page.content; let (ident, head) = head.split_at(8); if ident != b"OpusHead" { @@ -87,40 +122,38 @@ where data.read_exact(&mut channel_mapping)?; } - let mut sig = [0; 4]; - data.read_exact(&mut sig)?; - - if &sig != b"OggS" { - return Err(Error::UnknownFormat); - } - - let mut second_page = [0; 23]; - data.read_exact(&mut second_page)?; - - let size_pos = data.seek(SeekFrom::Current(0))? as usize; - - let mut segment_table = vec![0; second_page[22] as usize]; - data.read_exact(&mut segment_table)?; - - let start = data.seek(SeekFrom::Current(0))? as usize; - - let mut tags = vec![0; segment_table.iter().map(|&b| b as usize).sum()]; - data.read_exact(&mut tags)?; - - let end = data.seek(SeekFrom::Current(0))? as usize; + let second_page = read_page(&mut data)?; + let tags = second_page.content; + let size_pos = second_page.size_idx; + let start = second_page.start; + let end = second_page.end; if &tags[0..8] != b"OpusTags" { return Err(Error::UnknownFormat); } + let last_len = (packet.len() % 255) as u8; + let needed = (packet.len() / 255) + 1; + + let mut segments = Vec::with_capacity(needed); + + for i in 0..needed { + if i + 1 < needed { + segments.push(255) + } else { + segments.push(last_len) + } + } + data.seek(SeekFrom::Start(0))?; let mut content = Vec::new(); data.read_to_end(&mut content)?; content.splice(start..end, packet.to_vec()); - content.insert(size_pos, (packet.len() % 255) as u8); - content.remove(size_pos + 1); + content.insert(size_pos - 1, needed as u8); + content.remove(size_pos); + content.splice(size_pos..start, segments); Ok(content) }