mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2024-12-13 22:22:31 +00:00
Misc: Remove id3v2{_restrictions}
features
This commit is contained in:
parent
39c338e15b
commit
823f931d31
24 changed files with 112 additions and 203 deletions
|
@ -30,9 +30,8 @@ once_cell = "1.16.0"
|
||||||
paste = "1.0.11"
|
paste = "1.0.11"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["id3v2"]
|
default = ["id3v2_compression_support"]
|
||||||
id3v2 = ["flate2"]
|
id3v2_compression_support = ["flate2"]
|
||||||
id3v2_restrictions = []
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
# WAV properties validity tests
|
# WAV properties validity tests
|
||||||
|
|
|
@ -20,7 +20,6 @@ pub use properties::AACProperties;
|
||||||
#[lofty(read_fn = "read::read_from")]
|
#[lofty(read_fn = "read::read_from")]
|
||||||
#[lofty(internal_write_module_do_not_use_anywhere_else)]
|
#[lofty(internal_write_module_do_not_use_anywhere_else)]
|
||||||
pub struct AACFile {
|
pub struct AACFile {
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
#[lofty(tag_type = "ID3v2")]
|
#[lofty(tag_type = "ID3v2")]
|
||||||
pub(crate) id3v2_tag: Option<ID3v2Tag>,
|
pub(crate) id3v2_tag: Option<ID3v2Tag>,
|
||||||
#[lofty(tag_type = "ID3v1")]
|
#[lofty(tag_type = "ID3v1")]
|
||||||
|
|
|
@ -48,8 +48,6 @@ where
|
||||||
|
|
||||||
stream_len -= u64::from(header.size);
|
stream_len -= u64::from(header.size);
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
{
|
|
||||||
let id3v2 = parse_id3v2(reader, header)?;
|
let id3v2 = parse_id3v2(reader, header)?;
|
||||||
if let Some(existing_tag) = &mut file.id3v2_tag {
|
if let Some(existing_tag) = &mut file.id3v2_tag {
|
||||||
// https://github.com/Serial-ATA/lofty-rs/issues/87
|
// https://github.com/Serial-ATA/lofty-rs/issues/87
|
||||||
|
@ -60,7 +58,6 @@ where
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
file.id3v2_tag = Some(id3v2);
|
file.id3v2_tag = Some(id3v2);
|
||||||
}
|
|
||||||
|
|
||||||
// Skip over the footer
|
// Skip over the footer
|
||||||
if skip_footer {
|
if skip_footer {
|
||||||
|
|
|
@ -12,7 +12,6 @@ mod read;
|
||||||
pub(crate) mod tag;
|
pub(crate) mod tag;
|
||||||
|
|
||||||
use crate::id3::v1::tag::ID3v1Tag;
|
use crate::id3::v1::tag::ID3v1Tag;
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
use crate::id3::v2::tag::ID3v2Tag;
|
use crate::id3::v2::tag::ID3v2Tag;
|
||||||
|
|
||||||
use lofty_attr::LoftyFile;
|
use lofty_attr::LoftyFile;
|
||||||
|
@ -33,7 +32,6 @@ pub struct ApeFile {
|
||||||
#[lofty(tag_type = "ID3v1")]
|
#[lofty(tag_type = "ID3v1")]
|
||||||
pub(crate) id3v1_tag: Option<ID3v1Tag>,
|
pub(crate) id3v1_tag: Option<ID3v1Tag>,
|
||||||
/// An ID3v2 tag (Not officially supported)
|
/// An ID3v2 tag (Not officially supported)
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
#[lofty(tag_type = "ID3v2")]
|
#[lofty(tag_type = "ID3v2")]
|
||||||
pub(crate) id3v2_tag: Option<ID3v2Tag>,
|
pub(crate) id3v2_tag: Option<ID3v2Tag>,
|
||||||
/// An APEv1/v2 tag
|
/// An APEv1/v2 tag
|
||||||
|
|
|
@ -5,8 +5,8 @@ use super::tag::ApeTag;
|
||||||
use super::{ApeFile, ApeProperties};
|
use super::{ApeFile, ApeProperties};
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::id3::v1::tag::ID3v1Tag;
|
use crate::id3::v1::tag::ID3v1Tag;
|
||||||
#[cfg(feature = "id3v2")]
|
use crate::id3::v2::read::parse_id3v2;
|
||||||
use crate::id3::v2::{read::parse_id3v2, tag::ID3v2Tag};
|
use crate::id3::v2::tag::ID3v2Tag;
|
||||||
use crate::id3::{find_id3v1, find_id3v2, find_lyrics3v2, ID3FindResults};
|
use crate::id3::{find_id3v1, find_id3v2, find_lyrics3v2, ID3FindResults};
|
||||||
use crate::macros::decode_err;
|
use crate::macros::decode_err;
|
||||||
use crate::probe::ParseOptions;
|
use crate::probe::ParseOptions;
|
||||||
|
@ -24,7 +24,6 @@ where
|
||||||
|
|
||||||
let mut stream_len = end - start;
|
let mut stream_len = end - start;
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
let mut id3v2_tag: Option<ID3v2Tag> = None;
|
let mut id3v2_tag: Option<ID3v2Tag> = None;
|
||||||
let mut id3v1_tag: Option<ID3v1Tag> = None;
|
let mut id3v1_tag: Option<ID3v1Tag> = None;
|
||||||
let mut ape_tag: Option<ApeTag> = None;
|
let mut ape_tag: Option<ApeTag> = None;
|
||||||
|
@ -39,13 +38,10 @@ where
|
||||||
stream_len -= 10;
|
stream_len -= 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
{
|
|
||||||
let reader = &mut &*content;
|
let reader = &mut &*content;
|
||||||
|
|
||||||
let id3v2 = parse_id3v2(reader, header)?;
|
let id3v2 = parse_id3v2(reader, header)?;
|
||||||
id3v2_tag = Some(id3v2)
|
id3v2_tag = Some(id3v2);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut found_mac = false;
|
let mut found_mac = false;
|
||||||
|
@ -133,7 +129,6 @@ where
|
||||||
|
|
||||||
Ok(ApeFile {
|
Ok(ApeFile {
|
||||||
id3v1_tag,
|
id3v1_tag,
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
id3v2_tag,
|
id3v2_tag,
|
||||||
ape_tag,
|
ape_tag,
|
||||||
properties: if parse_options.read_properties {
|
properties: if parse_options.read_properties {
|
||||||
|
|
10
src/error.rs
10
src/error.rs
|
@ -70,21 +70,16 @@ pub enum ErrorKind {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum ID3v2ErrorKind {
|
pub enum ID3v2ErrorKind {
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
/// Arises when an invalid picture format is parsed. Only applicable to [`ID3v2Version::V2`](crate::id3::v2::ID3v2Version::V2)
|
/// Arises when an invalid picture format is parsed. Only applicable to [`ID3v2Version::V2`](crate::id3::v2::ID3v2Version::V2)
|
||||||
BadPictureFormat(String),
|
BadPictureFormat(String),
|
||||||
/// Arises when an invalid ID3v2 version is found
|
/// Arises when an invalid ID3v2 version is found
|
||||||
BadId3v2Version(u8, u8),
|
BadId3v2Version(u8, u8),
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
/// Arises when a frame ID contains invalid characters (must be within `'A'..'Z'` or `'0'..'9'`)
|
/// Arises when a frame ID contains invalid characters (must be within `'A'..'Z'` or `'0'..'9'`)
|
||||||
BadFrameID,
|
BadFrameID,
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
/// Arises when a frame doesn't have enough data
|
/// Arises when a frame doesn't have enough data
|
||||||
BadFrameLength,
|
BadFrameLength,
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
/// Arises when invalid data is encountered while reading an ID3v2 synchronized text frame
|
/// Arises when invalid data is encountered while reading an ID3v2 synchronized text frame
|
||||||
BadSyncText,
|
BadSyncText,
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
/// Arises when attempting to write an invalid Frame (Bad `FrameID`/`FrameValue` pairing)
|
/// Arises when attempting to write an invalid Frame (Bad `FrameID`/`FrameValue` pairing)
|
||||||
BadFrame(String, &'static str),
|
BadFrame(String, &'static str),
|
||||||
/// A catch-all for all remaining errors
|
/// A catch-all for all remaining errors
|
||||||
|
@ -101,22 +96,17 @@ impl Display for ID3v2ErrorKind {
|
||||||
"Found an invalid version (v{major}.{minor}), expected any major revision in: (2, \
|
"Found an invalid version (v{major}.{minor}), expected any major revision in: (2, \
|
||||||
3, 4)"
|
3, 4)"
|
||||||
),
|
),
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
ID3v2ErrorKind::BadFrameID => write!(f, "Failed to parse a frame ID"),
|
ID3v2ErrorKind::BadFrameID => write!(f, "Failed to parse a frame ID"),
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
ID3v2ErrorKind::BadFrameLength => write!(
|
ID3v2ErrorKind::BadFrameLength => write!(
|
||||||
f,
|
f,
|
||||||
"Frame isn't long enough to extract the necessary information"
|
"Frame isn't long enough to extract the necessary information"
|
||||||
),
|
),
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
ID3v2ErrorKind::BadSyncText => write!(f, "Encountered invalid data in SYLT frame"),
|
ID3v2ErrorKind::BadSyncText => write!(f, "Encountered invalid data in SYLT frame"),
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
ID3v2ErrorKind::BadFrame(ref frame_id, frame_value) => write!(
|
ID3v2ErrorKind::BadFrame(ref frame_id, frame_value) => write!(
|
||||||
f,
|
f,
|
||||||
"Attempted to write an invalid frame. ID: \"{}\", Value: \"{}\"",
|
"Attempted to write an invalid frame. ID: \"{}\", Value: \"{}\"",
|
||||||
frame_id, frame_value
|
frame_id, frame_value
|
||||||
),
|
),
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
ID3v2ErrorKind::BadPictureFormat(format) => {
|
ID3v2ErrorKind::BadPictureFormat(format) => {
|
||||||
write!(f, "Picture: Found unexpected format \"{format}\"")
|
write!(f, "Picture: Found unexpected format \"{format}\"")
|
||||||
},
|
},
|
||||||
|
|
|
@ -817,7 +817,6 @@ impl FileType {
|
||||||
/// ```
|
/// ```
|
||||||
pub fn supports_tag_type(&self, tag_type: TagType) -> bool {
|
pub fn supports_tag_type(&self, tag_type: TagType) -> bool {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
FileType::AIFF | FileType::APE | FileType::MPEG | FileType::WAV | FileType::AAC
|
FileType::AIFF | FileType::APE | FileType::MPEG | FileType::WAV | FileType::AAC
|
||||||
if tag_type == TagType::ID3v2 =>
|
if tag_type == TagType::ID3v2 =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,7 +9,6 @@ pub(crate) mod properties;
|
||||||
mod read;
|
mod read;
|
||||||
pub(crate) mod write;
|
pub(crate) mod write;
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
use crate::id3::v2::tag::ID3v2Tag;
|
use crate::id3::v2::tag::ID3v2Tag;
|
||||||
use crate::ogg::VorbisComments;
|
use crate::ogg::VorbisComments;
|
||||||
use crate::properties::FileProperties;
|
use crate::properties::FileProperties;
|
||||||
|
@ -29,7 +28,6 @@ use lofty_attr::LoftyFile;
|
||||||
#[lofty(read_fn = "read::read_from")]
|
#[lofty(read_fn = "read::read_from")]
|
||||||
pub struct FlacFile {
|
pub struct FlacFile {
|
||||||
/// An ID3v2 tag
|
/// An ID3v2 tag
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
#[lofty(tag_type = "ID3v2")]
|
#[lofty(tag_type = "ID3v2")]
|
||||||
pub(crate) id3v2_tag: Option<ID3v2Tag>,
|
pub(crate) id3v2_tag: Option<ID3v2Tag>,
|
||||||
/// The vorbis comments contained in the file
|
/// The vorbis comments contained in the file
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use super::block::Block;
|
use super::block::Block;
|
||||||
use super::FlacFile;
|
use super::FlacFile;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
use crate::id3::v2::read::parse_id3v2;
|
use crate::id3::v2::read::parse_id3v2;
|
||||||
use crate::id3::{find_id3v2, ID3FindResults};
|
use crate::id3::{find_id3v2, ID3FindResults};
|
||||||
use crate::macros::decode_err;
|
use crate::macros::decode_err;
|
||||||
|
@ -38,7 +37,6 @@ where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
let mut flac_file = FlacFile {
|
let mut flac_file = FlacFile {
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
id3v2_tag: None,
|
id3v2_tag: None,
|
||||||
vorbis_comments_tag: None,
|
vorbis_comments_tag: None,
|
||||||
properties: FileProperties::default(),
|
properties: FileProperties::default(),
|
||||||
|
@ -46,13 +44,10 @@ where
|
||||||
|
|
||||||
// It is possible for a FLAC file to contain an ID3v2 tag
|
// It is possible for a FLAC file to contain an ID3v2 tag
|
||||||
if let ID3FindResults(Some(header), Some(content)) = find_id3v2(data, true)? {
|
if let ID3FindResults(Some(header), Some(content)) = find_id3v2(data, true)? {
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
{
|
|
||||||
let reader = &mut &*content;
|
let reader = &mut &*content;
|
||||||
|
|
||||||
let id3v2 = parse_id3v2(reader, header)?;
|
let id3v2 = parse_id3v2(reader, header)?;
|
||||||
flac_file.id3v2_tag = Some(id3v2)
|
flac_file.id3v2_tag = Some(id3v2);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let stream_info = verify_flac(data)?;
|
let stream_info = verify_flac(data)?;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#[cfg(feature = "id3v2_restrictions")]
|
|
||||||
use super::restrictions::TagRestrictions;
|
use super::restrictions::TagRestrictions;
|
||||||
|
|
||||||
/// Flags that apply to the entire tag
|
/// Flags that apply to the entire tag
|
||||||
|
@ -17,7 +16,6 @@ pub struct ID3v2TagFlags {
|
||||||
///
|
///
|
||||||
/// This is calculated if the tag is written
|
/// This is calculated if the tag is written
|
||||||
pub crc: bool,
|
pub crc: bool,
|
||||||
#[cfg(feature = "id3v2_restrictions")]
|
|
||||||
/// Restrictions on the tag, written in the extended header
|
/// Restrictions on the tag, written in the extended header
|
||||||
///
|
///
|
||||||
/// In addition to being setting this flag, all restrictions must be provided. See [`TagRestrictions`]
|
/// In addition to being setting this flag, all restrictions must be provided. See [`TagRestrictions`]
|
||||||
|
|
|
@ -31,6 +31,7 @@ impl Frame {
|
||||||
content = crate::id3::v2::util::unsynch_content(content.as_slice())?;
|
content = crate::id3::v2::util::unsynch_content(content.as_slice())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "id3v2_compression_support")]
|
||||||
if flags.compression {
|
if flags.compression {
|
||||||
let mut decompressed = Vec::new();
|
let mut decompressed = Vec::new();
|
||||||
flate2::Decompress::new(true)
|
flate2::Decompress::new(true)
|
||||||
|
@ -44,6 +45,11 @@ impl Frame {
|
||||||
content = decompressed
|
content = decompressed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "id3v2_compression_support"))]
|
||||||
|
if flags.compression {
|
||||||
|
crate::macros::decode_err!(@BAIL ID3v2, "Encountered a compressed ID3v2 frame, support is disabled")
|
||||||
|
}
|
||||||
|
|
||||||
let mut content_reader = &*content;
|
let mut content_reader = &*content;
|
||||||
|
|
||||||
// Get the encryption method symbol
|
// Get the encryption method symbol
|
||||||
|
|
|
@ -8,7 +8,13 @@
|
||||||
//! * [Frame]
|
//! * [Frame]
|
||||||
|
|
||||||
mod flags;
|
mod flags;
|
||||||
|
mod frame;
|
||||||
|
mod items;
|
||||||
|
pub(crate) mod read;
|
||||||
|
mod restrictions;
|
||||||
|
pub(crate) mod tag;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
pub(crate) mod write;
|
||||||
|
|
||||||
use crate::error::{ID3v2Error, ID3v2ErrorKind, Result};
|
use crate::error::{ID3v2Error, ID3v2ErrorKind, Result};
|
||||||
use crate::macros::err;
|
use crate::macros::err;
|
||||||
|
@ -18,42 +24,26 @@ use std::io::Read;
|
||||||
|
|
||||||
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
|
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
// Exports
|
||||||
if #[cfg(feature = "id3v2")] {
|
|
||||||
pub use flags::ID3v2TagFlags;
|
pub use flags::ID3v2TagFlags;
|
||||||
pub use util::upgrade::{upgrade_v2, upgrade_v3};
|
pub use util::upgrade::{upgrade_v2, upgrade_v3};
|
||||||
|
|
||||||
pub(crate) mod tag;
|
|
||||||
pub use tag::ID3v2Tag;
|
pub use tag::ID3v2Tag;
|
||||||
|
|
||||||
mod items;
|
pub use items::encapsulated_object::{GEOBInformation, GeneralEncapsulatedObject};
|
||||||
pub use items::encoded_text_frame::EncodedTextFrame;
|
pub use items::encoded_text_frame::EncodedTextFrame;
|
||||||
pub use items::language_frame::LanguageFrame;
|
pub use items::language_frame::LanguageFrame;
|
||||||
pub use items::encapsulated_object::{GEOBInformation, GeneralEncapsulatedObject};
|
pub use items::sync_text::{
|
||||||
pub use items::sync_text::{SyncTextContentType, SyncTextInformation, SynchronizedText, TimestampFormat};
|
SyncTextContentType, SyncTextInformation, SynchronizedText, TimestampFormat,
|
||||||
|
};
|
||||||
|
|
||||||
mod frame;
|
|
||||||
pub use frame::id::FrameID;
|
pub use frame::id::FrameID;
|
||||||
pub use frame::Frame;
|
pub use frame::{Frame, FrameFlags, FrameValue};
|
||||||
pub use frame::FrameFlags;
|
|
||||||
pub use frame::FrameValue;
|
|
||||||
|
|
||||||
pub(crate) mod read;
|
|
||||||
pub(crate) mod write;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
|
||||||
if #[cfg(feature = "id3v2_restrictions")] {
|
|
||||||
mod restrictions;
|
|
||||||
pub use restrictions::{
|
pub use restrictions::{
|
||||||
ImageSizeRestrictions, TagRestrictions, TagSizeRestrictions, TextSizeRestrictions,
|
ImageSizeRestrictions, TagRestrictions, TagSizeRestrictions, TextSizeRestrictions,
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "id3v2"))]
|
|
||||||
use flags::ID3v2TagFlags;
|
|
||||||
|
|
||||||
/// The ID3v2 version
|
/// The ID3v2 version
|
||||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||||
|
@ -68,7 +58,6 @@ pub enum ID3v2Version {
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) struct ID3v2Header {
|
pub(crate) struct ID3v2Header {
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
pub version: ID3v2Version,
|
pub version: ID3v2Version,
|
||||||
pub flags: ID3v2TagFlags,
|
pub flags: ID3v2TagFlags,
|
||||||
pub size: u32,
|
pub size: u32,
|
||||||
|
@ -115,7 +104,6 @@ where
|
||||||
footer: (version == ID3v2Version::V4 || version == ID3v2Version::V3)
|
footer: (version == ID3v2Version::V4 || version == ID3v2Version::V3)
|
||||||
&& flags & 0x10 == 0x10,
|
&& flags & 0x10 == 0x10,
|
||||||
crc: false, // Retrieved later if applicable
|
crc: false, // Retrieved later if applicable
|
||||||
#[cfg(feature = "id3v2_restrictions")]
|
|
||||||
restrictions: None, // Retrieved later if applicable
|
restrictions: None, // Retrieved later if applicable
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -150,7 +138,6 @@ where
|
||||||
bytes.read_exact(&mut crc)?;
|
bytes.read_exact(&mut crc)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "id3v2_restrictions")]
|
|
||||||
if extended_flags & 0x10 == 0x10 {
|
if extended_flags & 0x10 == 0x10 {
|
||||||
// We don't care about the length byte, it is always 1
|
// We don't care about the length byte, it is always 1
|
||||||
let _data_length = bytes.read_u8()?;
|
let _data_length = bytes.read_u8()?;
|
||||||
|
@ -164,7 +151,6 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ID3v2Header {
|
Ok(ID3v2Header {
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
version,
|
version,
|
||||||
flags: flags_parsed,
|
flags: flags_parsed,
|
||||||
size,
|
size,
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
//! Utilities for working with ID3v2 tags
|
//! Utilities for working with ID3v2 tags
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
|
||||||
if #[cfg(feature = "id3v2")] {
|
|
||||||
pub(crate) mod upgrade;
|
pub(crate) mod upgrade;
|
||||||
|
|
||||||
use crate::error::{ID3v2Error, ID3v2ErrorKind, Result};
|
use crate::error::{ID3v2Error, ID3v2ErrorKind, Result};
|
||||||
|
@ -68,8 +66,6 @@ cfg_if::cfg_if! {
|
||||||
x = x & 0x7F_FFFF | (x & 0xFF80_0000) << 1;
|
x = x & 0x7F_FFFF | (x & 0xFF80_0000) << 1;
|
||||||
Ok(x)
|
Ok(x)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unsynchronise a synchsafe integer
|
/// Unsynchronise a synchsafe integer
|
||||||
///
|
///
|
||||||
|
|
|
@ -105,7 +105,6 @@ pub(super) fn create_tag<'a, I: Iterator<Item = FrameRef<'a>> + 'a>(
|
||||||
|
|
||||||
let has_footer = tag.flags.footer;
|
let has_footer = tag.flags.footer;
|
||||||
let needs_crc = tag.flags.crc;
|
let needs_crc = tag.flags.crc;
|
||||||
#[cfg(feature = "id3v2_restrictions")]
|
|
||||||
let has_restrictions = tag.flags.restrictions.is_some();
|
let has_restrictions = tag.flags.restrictions.is_some();
|
||||||
|
|
||||||
let (mut id3v2, extended_header_len) = create_tag_header(tag.flags)?;
|
let (mut id3v2, extended_header_len) = create_tag_header(tag.flags)?;
|
||||||
|
@ -126,7 +125,6 @@ pub(super) fn create_tag<'a, I: Iterator<Item = FrameRef<'a>> + 'a>(
|
||||||
// Past the CRC
|
// Past the CRC
|
||||||
let mut content_start_idx = 22;
|
let mut content_start_idx = 22;
|
||||||
|
|
||||||
#[cfg(feature = "id3v2_restrictions")]
|
|
||||||
if has_restrictions {
|
if has_restrictions {
|
||||||
content_start_idx += 3;
|
content_start_idx += 3;
|
||||||
}
|
}
|
||||||
|
@ -169,10 +167,6 @@ fn create_tag_header(flags: ID3v2TagFlags) -> Result<(Cursor<Vec<u8>>, u32)> {
|
||||||
// Version 4, rev 0
|
// Version 4, rev 0
|
||||||
header.write_all(&[4, 0])?;
|
header.write_all(&[4, 0])?;
|
||||||
|
|
||||||
#[cfg(not(feature = "id3v2_restrictions"))]
|
|
||||||
let extended_header = flags.crc;
|
|
||||||
|
|
||||||
#[cfg(feature = "id3v2_restrictions")]
|
|
||||||
let extended_header = flags.crc || flags.restrictions.is_some();
|
let extended_header = flags.crc || flags.restrictions.is_some();
|
||||||
|
|
||||||
if flags.footer {
|
if flags.footer {
|
||||||
|
@ -212,7 +206,6 @@ fn create_tag_header(flags: ID3v2TagFlags) -> Result<(Cursor<Vec<u8>>, u32)> {
|
||||||
header.write_all(&[0; 6])?;
|
header.write_all(&[0; 6])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "id3v2_restrictions")]
|
|
||||||
if let Some(restrictions) = flags.restrictions {
|
if let Some(restrictions) = flags.restrictions {
|
||||||
ext_flags |= 0x10;
|
ext_flags |= 0x10;
|
||||||
extended_header_size += 2;
|
extended_header_size += 2;
|
||||||
|
|
|
@ -4,7 +4,6 @@ mod properties;
|
||||||
mod read;
|
mod read;
|
||||||
pub(crate) mod tag;
|
pub(crate) mod tag;
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
use crate::id3::v2::tag::ID3v2Tag;
|
use crate::id3::v2::tag::ID3v2Tag;
|
||||||
use crate::properties::FileProperties;
|
use crate::properties::FileProperties;
|
||||||
|
|
||||||
|
@ -23,7 +22,6 @@ pub struct AiffFile {
|
||||||
#[lofty(tag_type = "AIFFText")]
|
#[lofty(tag_type = "AIFFText")]
|
||||||
pub(crate) text_chunks_tag: Option<AIFFTextChunks>,
|
pub(crate) text_chunks_tag: Option<AIFFTextChunks>,
|
||||||
/// An ID3v2 tag
|
/// An ID3v2 tag
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
#[lofty(tag_type = "ID3v2")]
|
#[lofty(tag_type = "ID3v2")]
|
||||||
pub(crate) id3v2_tag: Option<ID3v2Tag>,
|
pub(crate) id3v2_tag: Option<ID3v2Tag>,
|
||||||
/// The file's audio properties
|
/// The file's audio properties
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use super::tag::{AIFFTextChunks, Comment};
|
use super::tag::{AIFFTextChunks, Comment};
|
||||||
use super::AiffFile;
|
use super::AiffFile;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
use crate::id3::v2::tag::ID3v2Tag;
|
use crate::id3::v2::tag::ID3v2Tag;
|
||||||
use crate::iff::chunk::Chunks;
|
use crate::iff::chunk::Chunks;
|
||||||
use crate::macros::{decode_err, err};
|
use crate::macros::{decode_err, err};
|
||||||
|
@ -46,14 +45,12 @@ where
|
||||||
let mut annotations = Vec::new();
|
let mut annotations = Vec::new();
|
||||||
let mut comments = Vec::new();
|
let mut comments = Vec::new();
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
let mut id3v2_tag: Option<ID3v2Tag> = None;
|
let mut id3v2_tag: Option<ID3v2Tag> = None;
|
||||||
|
|
||||||
let mut chunks = Chunks::<BigEndian>::new(file_len);
|
let mut chunks = Chunks::<BigEndian>::new(file_len);
|
||||||
|
|
||||||
while chunks.next(data).is_ok() {
|
while chunks.next(data).is_ok() {
|
||||||
match &chunks.fourcc {
|
match &chunks.fourcc {
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
b"ID3 " | b"id3 " => {
|
b"ID3 " | b"id3 " => {
|
||||||
let tag = chunks.id3_chunk(data)?;
|
let tag = chunks.id3_chunk(data)?;
|
||||||
if let Some(existing_tag) = id3v2_tag.as_mut() {
|
if let Some(existing_tag) = id3v2_tag.as_mut() {
|
||||||
|
@ -159,7 +156,6 @@ where
|
||||||
} => None,
|
} => None,
|
||||||
_ => Some(text_chunks),
|
_ => Some(text_chunks),
|
||||||
},
|
},
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
id3v2_tag,
|
id3v2_tag,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
use crate::id3::v2::tag::ID3v2Tag;
|
use crate::id3::v2::tag::ID3v2Tag;
|
||||||
use crate::macros::{err, try_vec};
|
use crate::macros::{err, try_vec};
|
||||||
|
|
||||||
|
@ -91,7 +90,6 @@ impl<B: ByteOrder> Chunks<B> {
|
||||||
Ok(content)
|
Ok(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
pub fn id3_chunk<R>(&mut self, data: &mut R) -> Result<ID3v2Tag>
|
pub fn id3_chunk<R>(&mut self, data: &mut R) -> Result<ID3v2Tag>
|
||||||
where
|
where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
|
|
|
@ -4,7 +4,6 @@ mod properties;
|
||||||
mod read;
|
mod read;
|
||||||
pub(crate) mod tag;
|
pub(crate) mod tag;
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
use crate::id3::v2::tag::ID3v2Tag;
|
use crate::id3::v2::tag::ID3v2Tag;
|
||||||
|
|
||||||
use lofty_attr::LoftyFile;
|
use lofty_attr::LoftyFile;
|
||||||
|
@ -22,7 +21,6 @@ pub struct WavFile {
|
||||||
#[lofty(tag_type = "RIFFInfo")]
|
#[lofty(tag_type = "RIFFInfo")]
|
||||||
pub(crate) riff_info_tag: Option<RIFFInfoList>,
|
pub(crate) riff_info_tag: Option<RIFFInfoList>,
|
||||||
/// An ID3v2 tag
|
/// An ID3v2 tag
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
#[lofty(tag_type = "ID3v2")]
|
#[lofty(tag_type = "ID3v2")]
|
||||||
pub(crate) id3v2_tag: Option<ID3v2Tag>,
|
pub(crate) id3v2_tag: Option<ID3v2Tag>,
|
||||||
/// The file's audio properties
|
/// The file's audio properties
|
||||||
|
|
|
@ -2,7 +2,6 @@ use super::properties::WavProperties;
|
||||||
use super::tag::RIFFInfoList;
|
use super::tag::RIFFInfoList;
|
||||||
use super::WavFile;
|
use super::WavFile;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
use crate::id3::v2::tag::ID3v2Tag;
|
use crate::id3::v2::tag::ID3v2Tag;
|
||||||
use crate::iff::chunk::Chunks;
|
use crate::iff::chunk::Chunks;
|
||||||
use crate::macros::decode_err;
|
use crate::macros::decode_err;
|
||||||
|
@ -46,7 +45,6 @@ where
|
||||||
let mut fmt = Vec::new();
|
let mut fmt = Vec::new();
|
||||||
|
|
||||||
let mut riff_info = RIFFInfoList::default();
|
let mut riff_info = RIFFInfoList::default();
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
let mut id3v2_tag: Option<ID3v2Tag> = None;
|
let mut id3v2_tag: Option<ID3v2Tag> = None;
|
||||||
|
|
||||||
let mut chunks = Chunks::<LittleEndian>::new(file_len);
|
let mut chunks = Chunks::<LittleEndian>::new(file_len);
|
||||||
|
@ -89,7 +87,6 @@ where
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
b"ID3 " | b"id3 " => {
|
b"ID3 " | b"id3 " => {
|
||||||
let tag = chunks.id3_chunk(data)?;
|
let tag = chunks.id3_chunk(data)?;
|
||||||
if let Some(existing_tag) = id3v2_tag.as_mut() {
|
if let Some(existing_tag) = id3v2_tag.as_mut() {
|
||||||
|
@ -125,7 +122,6 @@ where
|
||||||
Ok(WavFile {
|
Ok(WavFile {
|
||||||
properties,
|
properties,
|
||||||
riff_info_tag: (!riff_info.items.is_empty()).then_some(riff_info),
|
riff_info_tag: (!riff_info.items.is_empty()).then_some(riff_info),
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
id3v2_tag,
|
id3v2_tag,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ pub use properties::MPEGProperties;
|
||||||
|
|
||||||
use crate::ape::tag::ApeTag;
|
use crate::ape::tag::ApeTag;
|
||||||
use crate::id3::v1::tag::ID3v1Tag;
|
use crate::id3::v1::tag::ID3v1Tag;
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
use crate::id3::v2::tag::ID3v2Tag;
|
use crate::id3::v2::tag::ID3v2Tag;
|
||||||
|
|
||||||
use lofty_attr::LoftyFile;
|
use lofty_attr::LoftyFile;
|
||||||
|
@ -20,7 +19,6 @@ use lofty_attr::LoftyFile;
|
||||||
#[lofty(internal_write_module_do_not_use_anywhere_else)]
|
#[lofty(internal_write_module_do_not_use_anywhere_else)]
|
||||||
pub struct MPEGFile {
|
pub struct MPEGFile {
|
||||||
/// An ID3v2 tag
|
/// An ID3v2 tag
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
#[lofty(tag_type = "ID3v2")]
|
#[lofty(tag_type = "ID3v2")]
|
||||||
pub(crate) id3v2_tag: Option<ID3v2Tag>,
|
pub(crate) id3v2_tag: Option<ID3v2Tag>,
|
||||||
/// An ID3v1 tag
|
/// An ID3v1 tag
|
||||||
|
|
|
@ -4,7 +4,6 @@ use crate::ape::constants::APE_PREAMBLE;
|
||||||
use crate::ape::header::read_ape_header;
|
use crate::ape::header::read_ape_header;
|
||||||
use crate::ape::tag::read::read_ape_tag;
|
use crate::ape::tag::read::read_ape_tag;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
use crate::id3::v2::read::parse_id3v2;
|
use crate::id3::v2::read::parse_id3v2;
|
||||||
use crate::id3::v2::read_id3v2_header;
|
use crate::id3::v2::read_id3v2_header;
|
||||||
use crate::id3::{find_id3v1, find_lyrics3v2, ID3FindResults};
|
use crate::id3::{find_id3v1, find_lyrics3v2, ID3FindResults};
|
||||||
|
@ -42,8 +41,6 @@ where
|
||||||
let header = read_id3v2_header(reader)?;
|
let header = read_id3v2_header(reader)?;
|
||||||
let skip_footer = header.flags.footer;
|
let skip_footer = header.flags.footer;
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
{
|
|
||||||
let id3v2 = parse_id3v2(reader, header)?;
|
let id3v2 = parse_id3v2(reader, header)?;
|
||||||
if let Some(existing_tag) = &mut file.id3v2_tag {
|
if let Some(existing_tag) = &mut file.id3v2_tag {
|
||||||
// https://github.com/Serial-ATA/lofty-rs/issues/87
|
// https://github.com/Serial-ATA/lofty-rs/issues/87
|
||||||
|
@ -54,7 +51,6 @@ where
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
file.id3v2_tag = Some(id3v2);
|
file.id3v2_tag = Some(id3v2);
|
||||||
}
|
|
||||||
|
|
||||||
// Skip over the footer
|
// Skip over the footer
|
||||||
if skip_footer {
|
if skip_footer {
|
||||||
|
|
|
@ -1,26 +1,13 @@
|
||||||
use crate::error::{ErrorKind, LoftyError, Result};
|
use crate::error::{ErrorKind, ID3v2Error, ID3v2ErrorKind, LoftyError, Result};
|
||||||
|
use crate::id3::v2::ID3v2Version;
|
||||||
use crate::macros::err;
|
use crate::macros::err;
|
||||||
#[cfg(feature = "id3v2")]
|
use crate::util::text::TextEncoding;
|
||||||
use crate::{
|
|
||||||
error::{ID3v2Error, ID3v2ErrorKind},
|
|
||||||
id3::v2::ID3v2Version,
|
|
||||||
};
|
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
#[cfg(any(feature = "id3v2"))]
|
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
use std::io::Cursor;
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
use std::io::Write;
|
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use crate::util::text::TextEncoding;
|
|
||||||
use byteorder::BigEndian;
|
|
||||||
#[cfg(any(feature = "id3v2"))]
|
|
||||||
use byteorder::ReadBytesExt;
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
use byteorder::WriteBytesExt;
|
|
||||||
|
|
||||||
/// Common picture item keys for APE
|
/// Common picture item keys for APE
|
||||||
pub const APE_PICTURE_TYPES: [&str; 21] = [
|
pub const APE_PICTURE_TYPES: [&str; 21] = [
|
||||||
|
@ -142,7 +129,6 @@ pub enum PictureType {
|
||||||
impl PictureType {
|
impl PictureType {
|
||||||
// ID3/OGG specific methods
|
// ID3/OGG specific methods
|
||||||
|
|
||||||
#[cfg(any(feature = "id3v2"))]
|
|
||||||
/// Get a u8 from a `PictureType` according to ID3v2 APIC
|
/// Get a u8 from a `PictureType` according to ID3v2 APIC
|
||||||
pub fn as_u8(&self) -> u8 {
|
pub fn as_u8(&self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
|
@ -171,7 +157,6 @@ impl PictureType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "id3v2"))]
|
|
||||||
/// Get a `PictureType` from a u8 according to ID3v2 APIC
|
/// Get a `PictureType` from a u8 according to ID3v2 APIC
|
||||||
pub fn from_u8(byte: u8) -> Self {
|
pub fn from_u8(byte: u8) -> Self {
|
||||||
match byte {
|
match byte {
|
||||||
|
@ -554,7 +539,6 @@ impl Picture {
|
||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
/// Convert a [`Picture`] to a ID3v2 A/PIC byte Vec
|
/// Convert a [`Picture`] to a ID3v2 A/PIC byte Vec
|
||||||
///
|
///
|
||||||
/// NOTE: This does not include the frame header
|
/// NOTE: This does not include the frame header
|
||||||
|
@ -618,7 +602,6 @@ impl Picture {
|
||||||
Ok(data)
|
Ok(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
/// Get a [`Picture`] and [`TextEncoding`] from ID3v2 A/PIC bytes:
|
/// Get a [`Picture`] and [`TextEncoding`] from ID3v2 A/PIC bytes:
|
||||||
///
|
///
|
||||||
/// NOTE: This expects *only* the frame content
|
/// NOTE: This expects *only* the frame content
|
||||||
|
|
|
@ -121,7 +121,6 @@ gen_map!(
|
||||||
);
|
);
|
||||||
|
|
||||||
gen_map!(
|
gen_map!(
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
ID3V2_MAP;
|
ID3V2_MAP;
|
||||||
|
|
||||||
"TALB" => AlbumTitle,
|
"TALB" => AlbumTitle,
|
||||||
|
@ -417,7 +416,6 @@ gen_item_keys!(
|
||||||
|
|
||||||
[TagType::APE, APE_MAP],
|
[TagType::APE, APE_MAP],
|
||||||
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
[TagType::ID3v2, ID3V2_MAP],
|
[TagType::ID3v2, ID3V2_MAP],
|
||||||
|
|
||||||
[TagType::MP4ilst, ILST_MAP],
|
[TagType::MP4ilst, ILST_MAP],
|
||||||
|
|
|
@ -5,8 +5,8 @@ use crate::tag::{Tag, TagType};
|
||||||
use crate::{aac, ape, flac, iff, mpeg, wavpack};
|
use crate::{aac, ape, flac, iff, mpeg, wavpack};
|
||||||
|
|
||||||
use crate::id3::v1::tag::Id3v1TagRef;
|
use crate::id3::v1::tag::Id3v1TagRef;
|
||||||
#[cfg(feature = "id3v2")]
|
use crate::id3::v2::tag::Id3v2TagRef;
|
||||||
use crate::id3::v2::{self, tag::Id3v2TagRef, ID3v2TagFlags};
|
use crate::id3::v2::{self, ID3v2TagFlags};
|
||||||
use crate::mp4::Ilst;
|
use crate::mp4::Ilst;
|
||||||
use crate::ogg::tag::{create_vorbis_comments_ref, VorbisCommentsRef};
|
use crate::ogg::tag::{create_vorbis_comments_ref, VorbisCommentsRef};
|
||||||
use ape::tag::ApeTagRef;
|
use ape::tag::ApeTagRef;
|
||||||
|
@ -45,7 +45,6 @@ pub(crate) fn dump_tag<W: Write>(tag: &Tag, writer: &mut W) -> Result<()> {
|
||||||
}
|
}
|
||||||
.dump_to(writer),
|
.dump_to(writer),
|
||||||
TagType::ID3v1 => Into::<Id3v1TagRef<'_>>::into(tag).dump_to(writer),
|
TagType::ID3v1 => Into::<Id3v1TagRef<'_>>::into(tag).dump_to(writer),
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
TagType::ID3v2 => Id3v2TagRef {
|
TagType::ID3v2 => Id3v2TagRef {
|
||||||
flags: ID3v2TagFlags::default(),
|
flags: ID3v2TagFlags::default(),
|
||||||
frames: v2::tag::tag_frames(tag),
|
frames: v2::tag::tag_frames(tag),
|
||||||
|
|
Loading…
Reference in a new issue