Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Don't error on empty `SYLT` strings ([issue](https://github.com/Serial-ATA/lofty-rs/issues/563)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/564))
- **Vorbis Comments**: Parse `TRACKNUMBER` with respect to `ParseOptions::implicit_conversions` ([issue](https://github.com/Serial-ATA/lofty-rs/issues/540)) ([PR](https://github.com/Serial-ATA/lofty-rs/issues/542))
- **APE**: Fix disc number removal/writing ([issue](https://github.com/Serial-ATA/lofty-rs/issues/545)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/546))
- **FLAC**: Fix corruption of files with no metadata blocks ([issue](https://github.com/Serial-ATA/lofty-rs/issues/549)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/583))

### Removed

Expand Down
89 changes: 84 additions & 5 deletions lofty/src/flac/block.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#![allow(dead_code)]

use crate::error::Result;
use crate::macros::try_vec;
use crate::macros::{err, try_vec};
use crate::picture::{Picture, PictureInformation};

use std::io::{Read, Seek, SeekFrom};
use std::io::{Cursor, Read, Seek, SeekFrom, Write};

use byteorder::{BigEndian, ReadBytesExt};
use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};

pub(in crate::flac) const BLOCK_ID_STREAMINFO: u8 = 0;
pub(in crate::flac) const BLOCK_ID_PADDING: u8 = 1;
Expand All @@ -16,7 +17,6 @@ pub(in crate::flac) const BLOCK_ID_PICTURE: u8 = 6;
const BLOCK_HEADER_SIZE: u64 = 4;

pub(crate) struct Block {
pub(super) byte: u8,
pub(super) ty: u8,
pub(super) last: bool,
pub(crate) content: Vec<u8>,
Expand All @@ -25,6 +25,9 @@ pub(crate) struct Block {
}

impl Block {
pub(super) const BLOCK_HEADER_SIZE: usize = 4;
pub(super) const MAX_CONTENT_SIZE: u32 = 16_777_215;

pub(crate) fn read<R, P>(data: &mut R, mut predicate: P) -> Result<Self>
where
R: Read + Seek,
Expand All @@ -51,12 +54,88 @@ impl Block {
let end = start + u64::from(size) + BLOCK_HEADER_SIZE;

Ok(Self {
byte,
ty,
last,
content,
start,
end,
})
}

pub fn len(&self) -> u32 {
(Self::BLOCK_HEADER_SIZE as u32) + self.content.len() as u32
}

pub(super) fn new_padding(size: usize) -> Result<Self> {
let block_size = core::cmp::min(size, Self::MAX_CONTENT_SIZE as usize);
let content = try_vec![0; block_size];
Ok(Self {
ty: BLOCK_ID_PADDING,
last: false,
content,
start: 0,
end: 0,
})
}

pub(super) fn new_picture(picture: &Picture, info: PictureInformation) -> Result<Self> {
let picture_data = picture.as_flac_bytes(info, false);
if picture_data.len() > Self::MAX_CONTENT_SIZE as usize {
err!(TooMuchData);
}

Ok(Self {
ty: BLOCK_ID_PICTURE,
last: false,
content: picture_data,
start: 0,
end: 0,
})
}

pub(super) fn new_comments<'a>(
vendor: &str,
items: &mut impl Iterator<Item = (&'a str, &'a str)>,
) -> Result<Self> {
let mut comments = Cursor::new(Vec::new());

comments.write_u32::<LittleEndian>(vendor.len() as u32)?;
comments.write_all(vendor.as_bytes())?;

let item_count_pos = comments.stream_position()?;
let mut count = 0;

comments.write_u32::<LittleEndian>(count)?;

crate::ogg::write::create_comments(&mut comments, &mut count, items)?;

if comments.get_ref().len() > Block::MAX_CONTENT_SIZE as usize {
err!(TooMuchData);
}

comments.seek(SeekFrom::Start(item_count_pos))?;
comments.write_u32::<LittleEndian>(count)?;

Ok(Self {
ty: BLOCK_ID_VORBIS_COMMENTS,
last: false,
content: comments.into_inner(),
start: 0,
end: 0,
})
}

pub(super) fn write_to<W>(&self, writer: &mut W) -> Result<usize>
where
W: Write,
{
let block_content_size =
core::cmp::min(self.content.len(), Self::MAX_CONTENT_SIZE as usize);

writer.write_u8((self.ty & 0x7F) | u8::from(self.last) << 7)?;
writer.write_u24::<BigEndian>(block_content_size as u32)?;
writer.write_all(&self.content)?;

Ok(Self::BLOCK_HEADER_SIZE + self.content.len())
}
}
Loading