mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2024-11-14 00:17:07 +00:00
Cleanup; Make use of doc_cfg
This commit is contained in:
parent
4e3cf7a882
commit
d13f01d215
22 changed files with 273 additions and 230 deletions
|
@ -54,4 +54,5 @@ name = "create_tag"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
58
src/ape/header.rs
Normal file
58
src/ape/header.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
use crate::error::{FileDecodingError, Result};
|
||||||
|
use crate::types::file::FileType;
|
||||||
|
|
||||||
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
use std::ops::Neg;
|
||||||
|
|
||||||
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub(crate) struct ApeHeader {
|
||||||
|
pub(crate) size: u32,
|
||||||
|
#[cfg(feature = "ape")]
|
||||||
|
pub(crate) item_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_ape_header<R>(data: &mut R, footer: bool) -> Result<ApeHeader>
|
||||||
|
where
|
||||||
|
R: Read + Seek,
|
||||||
|
{
|
||||||
|
let version = data.read_u32::<LittleEndian>()?;
|
||||||
|
|
||||||
|
let mut size = data.read_u32::<LittleEndian>()?;
|
||||||
|
|
||||||
|
if size < 32 {
|
||||||
|
// If the size is < 32, something went wrong during encoding
|
||||||
|
// The size includes the footer and all items
|
||||||
|
return Err(
|
||||||
|
FileDecodingError::new(FileType::APE, "APE tag has an invalid size (< 32)").into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ape")]
|
||||||
|
let item_count = data.read_u32::<LittleEndian>()?;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "ape"))]
|
||||||
|
data.seek(SeekFrom::Current(4))?;
|
||||||
|
|
||||||
|
if footer {
|
||||||
|
// No point in reading the rest of the footer, just seek back to the end of the header
|
||||||
|
data.seek(SeekFrom::Current(i64::from(size - 12).neg()))?;
|
||||||
|
} else {
|
||||||
|
// There are 12 bytes remaining in the header
|
||||||
|
// Flags (4)
|
||||||
|
// Reserved (8)
|
||||||
|
data.seek(SeekFrom::Current(12))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version 1 doesn't include a header
|
||||||
|
if version == 2000 {
|
||||||
|
size += 32
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ApeHeader {
|
||||||
|
size,
|
||||||
|
#[cfg(feature = "ape")]
|
||||||
|
item_count,
|
||||||
|
})
|
||||||
|
}
|
|
@ -6,30 +6,36 @@
|
||||||
//! this tag will be read, but **cannot** be written. The only tags allowed by spec are `APEv1/2` and
|
//! this tag will be read, but **cannot** be written. The only tags allowed by spec are `APEv1/2` and
|
||||||
//! `ID3v1`.
|
//! `ID3v1`.
|
||||||
pub(crate) mod constants;
|
pub(crate) mod constants;
|
||||||
|
pub(crate) mod header;
|
||||||
mod properties;
|
mod properties;
|
||||||
mod read;
|
mod read;
|
||||||
pub(crate) mod tag;
|
|
||||||
pub(crate) mod write;
|
pub(crate) mod write;
|
||||||
|
|
||||||
pub use crate::ape::properties::ApeProperties;
|
|
||||||
#[cfg(feature = "ape")]
|
|
||||||
pub use {
|
|
||||||
crate::types::picture::APE_PICTURE_TYPES,
|
|
||||||
tag::{ape_tag::ApeTag, item::ApeItem},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
#[cfg(feature = "id3v1")]
|
#[cfg(feature = "id3v1")]
|
||||||
use crate::id3::v1::tag::Id3v1Tag;
|
use crate::id3::v1::tag::Id3v1Tag;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::id3::v2::tag::Id3v2Tag;
|
use crate::id3::v2::tag::Id3v2Tag;
|
||||||
use crate::tag_utils::tag_methods;
|
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
use crate::types::properties::FileProperties;
|
use crate::types::properties::FileProperties;
|
||||||
use crate::types::tag::{Tag, TagType};
|
use crate::types::tag::{Tag, TagType};
|
||||||
|
|
||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
|
||||||
|
crate::macros::feature_locked! {
|
||||||
|
#![cfg(feature = "ape")]
|
||||||
|
|
||||||
|
pub(crate) mod tag;
|
||||||
|
pub use tag::ape_tag::ApeTag;
|
||||||
|
pub use tag::item::ApeItem;
|
||||||
|
|
||||||
|
pub use crate::types::picture::APE_PICTURE_TYPES;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use properties::ApeProperties;
|
||||||
|
|
||||||
/// An APE file
|
/// An APE file
|
||||||
pub struct ApeFile {
|
pub struct ApeFile {
|
||||||
#[cfg(feature = "id3v1")]
|
#[cfg(feature = "id3v1")]
|
||||||
|
@ -106,12 +112,14 @@ impl AudioFile for ApeFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApeFile {
|
impl ApeFile {
|
||||||
tag_methods! {
|
crate::macros::tag_methods! {
|
||||||
#[cfg(feature = "id3v2")];
|
#[cfg(feature = "id3v2")]
|
||||||
id3v2_tag, Id3v2Tag;
|
id3v2_tag, Id3v2Tag;
|
||||||
#[cfg(feature = "id3v1")];
|
|
||||||
|
#[cfg(feature = "id3v1")]
|
||||||
id3v1_tag, Id3v1Tag;
|
id3v1_tag, Id3v1Tag;
|
||||||
#[cfg(feature = "ape")];
|
|
||||||
|
#[cfg(feature = "ape")]
|
||||||
ape_tag, ApeTag
|
ape_tag, ApeTag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use super::constants::APE_PREAMBLE;
|
use super::constants::APE_PREAMBLE;
|
||||||
|
use super::header::read_ape_header;
|
||||||
#[cfg(feature = "ape")]
|
#[cfg(feature = "ape")]
|
||||||
use super::tag::{ape_tag::ApeTag, read::read_ape_tag};
|
use super::tag::{ape_tag::ApeTag, read::read_ape_tag};
|
||||||
use super::{ApeFile, ApeProperties};
|
use super::{ApeFile, ApeProperties};
|
||||||
use crate::ape::tag::read_ape_header;
|
|
||||||
use crate::error::{FileDecodingError, Result};
|
use crate::error::{FileDecodingError, Result};
|
||||||
#[cfg(feature = "id3v1")]
|
#[cfg(feature = "id3v1")]
|
||||||
use crate::id3::v1::tag::Id3v1Tag;
|
use crate::id3::v1::tag::Id3v1Tag;
|
||||||
|
|
|
@ -278,8 +278,8 @@ impl<'a> Into<ApeTagRef<'a>> for &'a ApeTag {
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::ape::{ApeItem, ApeTag};
|
use crate::ape::{ApeItem, ApeTag};
|
||||||
use crate::{ItemValue, Tag, TagIO, TagType};
|
use crate::{ItemValue, Tag, TagIO, TagType};
|
||||||
|
use crate::ape::header::read_ape_header;
|
||||||
|
|
||||||
use crate::ape::tag::read_ape_header;
|
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,67 +1,4 @@
|
||||||
#[cfg(feature = "ape")]
|
|
||||||
pub(crate) mod ape_tag;
|
pub(crate) mod ape_tag;
|
||||||
#[cfg(feature = "ape")]
|
|
||||||
pub(crate) mod item;
|
pub(crate) mod item;
|
||||||
#[cfg(feature = "ape")]
|
|
||||||
pub(crate) mod read;
|
pub(crate) mod read;
|
||||||
#[cfg(feature = "ape")]
|
mod write;
|
||||||
mod write;
|
|
||||||
|
|
||||||
use crate::error::{FileDecodingError, Result};
|
|
||||||
use crate::types::file::FileType;
|
|
||||||
|
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
|
||||||
use std::ops::Neg;
|
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt};
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub(crate) struct ApeHeader {
|
|
||||||
pub(crate) size: u32,
|
|
||||||
#[cfg(feature = "ape")]
|
|
||||||
pub(crate) item_count: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn read_ape_header<R>(data: &mut R, footer: bool) -> Result<ApeHeader>
|
|
||||||
where
|
|
||||||
R: Read + Seek,
|
|
||||||
{
|
|
||||||
let version = data.read_u32::<LittleEndian>()?;
|
|
||||||
|
|
||||||
let mut size = data.read_u32::<LittleEndian>()?;
|
|
||||||
|
|
||||||
if size < 32 {
|
|
||||||
// If the size is < 32, something went wrong during encoding
|
|
||||||
// The size includes the footer and all items
|
|
||||||
return Err(
|
|
||||||
FileDecodingError::new(FileType::APE, "APE tag has an invalid size (< 32)").into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ape")]
|
|
||||||
let item_count = data.read_u32::<LittleEndian>()?;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "ape"))]
|
|
||||||
data.seek(SeekFrom::Current(4))?;
|
|
||||||
|
|
||||||
if footer {
|
|
||||||
// No point in reading the rest of the footer, just seek back to the end of the header
|
|
||||||
data.seek(SeekFrom::Current(i64::from(size - 12).neg()))?;
|
|
||||||
} else {
|
|
||||||
// There are 12 bytes remaining in the header
|
|
||||||
// Flags (4)
|
|
||||||
// Reserved (8)
|
|
||||||
data.seek(SeekFrom::Current(12))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version 1 doesn't include a header
|
|
||||||
if version == 2000 {
|
|
||||||
size += 32
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ApeHeader {
|
|
||||||
size,
|
|
||||||
#[cfg(feature = "ape")]
|
|
||||||
item_count,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::ape_tag::ApeTag;
|
use super::ape_tag::ApeTag;
|
||||||
use super::item::ApeItem;
|
use super::item::ApeItem;
|
||||||
use super::ApeHeader;
|
use crate::ape::header::ApeHeader;
|
||||||
use crate::ape::constants::INVALID_KEYS;
|
use crate::ape::constants::INVALID_KEYS;
|
||||||
use crate::error::{FileDecodingError, Result};
|
use crate::error::{FileDecodingError, Result};
|
||||||
use crate::types::file::FileType;
|
use crate::types::file::FileType;
|
||||||
|
|
|
@ -6,11 +6,11 @@ use crate::id3::{find_id3v1, find_id3v2, find_lyrics3v2};
|
||||||
use crate::probe::Probe;
|
use crate::probe::Probe;
|
||||||
use crate::types::file::FileType;
|
use crate::types::file::FileType;
|
||||||
use crate::types::item::ItemValueRef;
|
use crate::types::item::ItemValueRef;
|
||||||
|
use crate::ape::header::read_ape_header;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
|
|
||||||
use crate::ape::tag::read_ape_header;
|
|
||||||
use byteorder::{LittleEndian, WriteBytesExt};
|
use byteorder::{LittleEndian, WriteBytesExt};
|
||||||
|
|
||||||
#[allow(clippy::shadow_unrelated)]
|
#[allow(clippy::shadow_unrelated)]
|
||||||
|
|
|
@ -15,12 +15,15 @@
|
||||||
//! A track number of 0 will be treated as an empty field.
|
//! A track number of 0 will be treated as an empty field.
|
||||||
//! Additionally, there is no track total field.
|
//! Additionally, there is no track total field.
|
||||||
pub(crate) mod constants;
|
pub(crate) mod constants;
|
||||||
#[cfg(feature = "id3v1")]
|
|
||||||
pub(crate) mod read;
|
|
||||||
#[cfg(feature = "id3v1")]
|
|
||||||
pub(crate) mod tag;
|
|
||||||
#[cfg(feature = "id3v1")]
|
|
||||||
pub(crate) mod write;
|
|
||||||
|
|
||||||
#[cfg(feature = "id3v1")]
|
crate::macros::feature_locked! {
|
||||||
pub use crate::id3::v1::{constants::GENRES, tag::Id3v1Tag};
|
#![cfg(feature = "id3v1")]
|
||||||
|
|
||||||
|
pub use constants::GENRES;
|
||||||
|
|
||||||
|
pub(crate) mod tag;
|
||||||
|
pub use tag::Id3v1Tag;
|
||||||
|
|
||||||
|
pub(crate) mod read;
|
||||||
|
pub(crate) mod write;
|
||||||
|
}
|
||||||
|
|
|
@ -8,51 +8,52 @@
|
||||||
//! * [Frame]
|
//! * [Frame]
|
||||||
|
|
||||||
mod flags;
|
mod flags;
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
mod frame;
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
mod items;
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
pub(crate) mod read;
|
|
||||||
#[cfg(feature = "id3v2_restrictions")]
|
|
||||||
mod restrictions;
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
pub(crate) mod tag;
|
|
||||||
pub(crate) mod util;
|
pub(crate) mod util;
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
pub(crate) mod write;
|
|
||||||
|
|
||||||
#[cfg(feature = "id3v2_restrictions")]
|
|
||||||
pub use restrictions::{
|
|
||||||
ImageSizeRestrictions, TagRestrictions, TagSizeRestrictions, TextSizeRestrictions,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "id3v2")]
|
|
||||||
pub use {
|
|
||||||
flags::Id3v2TagFlags,
|
|
||||||
frame::{
|
|
||||||
content::EncodedTextFrame, content::LanguageFrame, id::FrameID, Frame, FrameFlags,
|
|
||||||
FrameValue,
|
|
||||||
},
|
|
||||||
items::{
|
|
||||||
encapsulated_object::{GEOBInformation, GeneralEncapsulatedObject},
|
|
||||||
sync_text::{SyncTextContentType, SyncTextInformation, SynchronizedText, TimestampFormat},
|
|
||||||
},
|
|
||||||
tag::Id3v2Tag,
|
|
||||||
util::{
|
|
||||||
text_utils::TextEncoding,
|
|
||||||
upgrade::{upgrade_v2, upgrade_v3},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(not(feature = "id3v2"))]
|
|
||||||
use flags::Id3v2TagFlags;
|
|
||||||
|
|
||||||
use crate::error::{ErrorKind, Id3v2Error, Id3v2ErrorKind, LoftyError, Result};
|
use crate::error::{ErrorKind, Id3v2Error, Id3v2ErrorKind, LoftyError, Result};
|
||||||
|
use crate::macros::feature_locked;
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
|
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
|
||||||
|
|
||||||
|
feature_locked! {
|
||||||
|
#![cfg(feature = "id3v2")]
|
||||||
|
|
||||||
|
pub use flags::Id3v2TagFlags;
|
||||||
|
pub use util::text_utils::TextEncoding;
|
||||||
|
pub use util::upgrade::{upgrade_v2, upgrade_v3};
|
||||||
|
|
||||||
|
pub(crate) mod tag;
|
||||||
|
pub use tag::Id3v2Tag;
|
||||||
|
|
||||||
|
mod items;
|
||||||
|
pub use items::encapsulated_object::{GEOBInformation, GeneralEncapsulatedObject};
|
||||||
|
pub use items::sync_text::{SyncTextContentType, SyncTextInformation, SynchronizedText, TimestampFormat};
|
||||||
|
|
||||||
|
mod frame;
|
||||||
|
pub use frame::content::{EncodedTextFrame, LanguageFrame};
|
||||||
|
pub use frame::id::FrameID;
|
||||||
|
pub use frame::Frame;
|
||||||
|
pub use frame::FrameFlags;
|
||||||
|
pub use frame::FrameValue;
|
||||||
|
|
||||||
|
pub(crate) mod read;
|
||||||
|
pub(crate) mod write;
|
||||||
|
}
|
||||||
|
|
||||||
|
feature_locked! {
|
||||||
|
#![cfg(feature = "id3v2_restrictions")]
|
||||||
|
|
||||||
|
mod restrictions;
|
||||||
|
pub use restrictions::{
|
||||||
|
ImageSizeRestrictions, TagRestrictions, TagSizeRestrictions, TextSizeRestrictions,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "id3v2"))]
|
||||||
|
use flags::Id3v2TagFlags;
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||||
/// The ID3v2 version
|
/// The ID3v2 version
|
||||||
pub enum Id3v2Version {
|
pub enum Id3v2Version {
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
mod properties;
|
mod properties;
|
||||||
mod read;
|
mod read;
|
||||||
#[cfg(feature = "aiff_text_chunks")]
|
|
||||||
pub(crate) mod tag;
|
|
||||||
pub(crate) mod write;
|
pub(crate) mod write;
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::id3::v2::tag::Id3v2Tag;
|
use crate::id3::v2::tag::Id3v2Tag;
|
||||||
use crate::tag_utils::tag_methods;
|
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
use crate::types::properties::FileProperties;
|
use crate::types::properties::FileProperties;
|
||||||
use crate::types::tag::{Tag, TagType};
|
use crate::types::tag::{Tag, TagType};
|
||||||
#[cfg(feature = "aiff_text_chunks")]
|
|
||||||
use tag::AiffTextChunks;
|
|
||||||
|
|
||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
|
crate::macros::feature_locked! {
|
||||||
|
#![cfg(feature = "aiff_text_chunks")]
|
||||||
|
|
||||||
|
pub(crate) mod tag;
|
||||||
|
use tag::AiffTextChunks;
|
||||||
|
}
|
||||||
|
|
||||||
/// An AIFF file
|
/// An AIFF file
|
||||||
pub struct AiffFile {
|
pub struct AiffFile {
|
||||||
#[cfg(feature = "aiff_text_chunks")]
|
#[cfg(feature = "aiff_text_chunks")]
|
||||||
|
@ -83,10 +85,11 @@ impl AudioFile for AiffFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AiffFile {
|
impl AiffFile {
|
||||||
tag_methods! {
|
crate::macros::tag_methods! {
|
||||||
#[cfg(feature = "id3v2")];
|
#[cfg(feature = "id3v2")]
|
||||||
id3v2_tag, Id3v2Tag;
|
id3v2_tag, Id3v2Tag;
|
||||||
#[cfg(feature = "aiff_text_chunks")];
|
|
||||||
|
#[cfg(feature = "aiff_text_chunks")]
|
||||||
text_chunks, AiffTextChunks
|
text_chunks, AiffTextChunks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,22 @@ pub(crate) mod aiff;
|
||||||
pub(crate) mod chunk;
|
pub(crate) mod chunk;
|
||||||
pub(crate) mod wav;
|
pub(crate) mod wav;
|
||||||
|
|
||||||
|
use crate::macros::feature_locked;
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
|
||||||
pub use aiff::AiffFile;
|
pub use aiff::AiffFile;
|
||||||
pub use wav::{WavFile, WavFormat, WavProperties};
|
pub use wav::{WavFile, WavFormat, WavProperties};
|
||||||
|
|
||||||
#[cfg(feature = "aiff_text_chunks")]
|
feature_locked! {
|
||||||
pub use aiff::tag::{AiffTextChunks, Comment};
|
#![cfg(feature = "aiff_text_chunks")]
|
||||||
#[cfg(feature = "riff_info_list")]
|
|
||||||
pub use wav::tag::RiffInfoList;
|
pub use aiff::tag::AiffTextChunks;
|
||||||
|
pub use aiff::tag::Comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
feature_locked! {
|
||||||
|
#![cfg(feature = "riff_info_list")]
|
||||||
|
|
||||||
|
pub use wav::tag::RiffInfoList;
|
||||||
|
}
|
||||||
|
|
|
@ -1,23 +1,26 @@
|
||||||
mod properties;
|
mod properties;
|
||||||
mod read;
|
mod read;
|
||||||
#[cfg(feature = "riff_info_list")]
|
|
||||||
pub(crate) mod tag;
|
|
||||||
pub(crate) mod write;
|
pub(crate) mod write;
|
||||||
|
|
||||||
pub use crate::iff::wav::properties::{WavFormat, WavProperties};
|
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::id3::v2::tag::Id3v2Tag;
|
use crate::id3::v2::tag::Id3v2Tag;
|
||||||
use crate::tag_utils::tag_methods;
|
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
use crate::types::properties::FileProperties;
|
use crate::types::properties::FileProperties;
|
||||||
use crate::types::tag::{Tag, TagType};
|
use crate::types::tag::{Tag, TagType};
|
||||||
#[cfg(feature = "riff_info_list")]
|
|
||||||
use tag::RiffInfoList;
|
|
||||||
|
|
||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
|
crate::macros::feature_locked! {
|
||||||
|
#![cfg(feature = "riff_info_list")]
|
||||||
|
|
||||||
|
pub(crate) mod tag;
|
||||||
|
use tag::RiffInfoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
pub use crate::iff::wav::properties::{WavFormat, WavProperties};
|
||||||
|
|
||||||
/// A WAV file
|
/// A WAV file
|
||||||
pub struct WavFile {
|
pub struct WavFile {
|
||||||
#[cfg(feature = "riff_info_list")]
|
#[cfg(feature = "riff_info_list")]
|
||||||
|
@ -86,10 +89,11 @@ impl AudioFile for WavFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WavFile {
|
impl WavFile {
|
||||||
tag_methods! {
|
crate::macros::tag_methods! {
|
||||||
#[cfg(feature = "id3v2")];
|
#[cfg(feature = "id3v2")]
|
||||||
id3v2_tag, Id3v2Tag;
|
id3v2_tag, Id3v2Tag;
|
||||||
#[cfg(feature = "riff_info_list")];
|
|
||||||
|
#[cfg(feature = "riff_info_list")]
|
||||||
riff_info, RiffInfoList
|
riff_info, RiffInfoList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,11 +151,13 @@
|
||||||
clippy::tabs_in_doc_comments,
|
clippy::tabs_in_doc_comments,
|
||||||
clippy::len_without_is_empty
|
clippy::len_without_is_empty
|
||||||
)]
|
)]
|
||||||
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
|
||||||
pub mod ape;
|
pub mod ape;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod id3;
|
pub mod id3;
|
||||||
pub mod iff;
|
pub mod iff;
|
||||||
|
pub(crate) mod macros;
|
||||||
pub mod mp3;
|
pub mod mp3;
|
||||||
pub mod mp4;
|
pub mod mp4;
|
||||||
pub mod ogg;
|
pub mod ogg;
|
||||||
|
|
45
src/macros.rs
Normal file
45
src/macros.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
macro_rules! tag_methods {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
$(#[cfg($meta:meta)])?
|
||||||
|
$name:ident,
|
||||||
|
$ty:ty
|
||||||
|
);*
|
||||||
|
) => {
|
||||||
|
paste::paste! {
|
||||||
|
$(
|
||||||
|
$(#[cfg($meta)])?
|
||||||
|
#[doc = "Gets the [`" $ty "`] if it exists"]
|
||||||
|
pub fn $name(&self) -> Option<&$ty> {
|
||||||
|
self.$name.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
$(#[cfg($meta)])?
|
||||||
|
#[doc = "Gets a mutable reference to the [`" $ty "`] if it exists"]
|
||||||
|
pub fn [<$name _mut>](&mut self) -> Option<&mut $ty> {
|
||||||
|
self.$name.as_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
$(#[cfg($meta)])?
|
||||||
|
#[doc = "Removes the [`" $ty "`]"]
|
||||||
|
pub fn [<remove_ $name>](&mut self) {
|
||||||
|
self.$name = None
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! feature_locked {
|
||||||
|
(
|
||||||
|
#![cfg($meta:meta)]
|
||||||
|
$($item:item)+
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
#[cfg($meta)]
|
||||||
|
$item
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) use {feature_locked, tag_methods};
|
|
@ -15,7 +15,6 @@ use crate::error::Result;
|
||||||
use crate::id3::v1::tag::Id3v1Tag;
|
use crate::id3::v1::tag::Id3v1Tag;
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::id3::v2::tag::Id3v2Tag;
|
use crate::id3::v2::tag::Id3v2Tag;
|
||||||
use crate::tag_utils::tag_methods;
|
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
use crate::types::properties::FileProperties;
|
use crate::types::properties::FileProperties;
|
||||||
use crate::types::tag::{Tag, TagType};
|
use crate::types::tag::{Tag, TagType};
|
||||||
|
@ -100,12 +99,14 @@ impl AudioFile for Mp3File {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mp3File {
|
impl Mp3File {
|
||||||
tag_methods! {
|
crate::macros::tag_methods! {
|
||||||
#[cfg(feature = "id3v2")];
|
#[cfg(feature = "id3v2")]
|
||||||
id3v2_tag, Id3v2Tag;
|
id3v2_tag, Id3v2Tag;
|
||||||
#[cfg(feature = "id3v1")];
|
|
||||||
|
#[cfg(feature = "id3v1")]
|
||||||
id3v1_tag, Id3v1Tag;
|
id3v1_tag, Id3v1Tag;
|
||||||
#[cfg(feature = "ape")];
|
|
||||||
|
#[cfg(feature = "ape")]
|
||||||
ape_tag, ApeTag
|
ape_tag, ApeTag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use super::header::{search_for_frame_sync, Header, XingHeader};
|
use super::header::{search_for_frame_sync, Header, XingHeader};
|
||||||
use super::{Mp3File, Mp3Properties};
|
use super::{Mp3File, Mp3Properties};
|
||||||
use crate::ape::constants::APE_PREAMBLE;
|
use crate::ape::constants::APE_PREAMBLE;
|
||||||
|
use crate::ape::header::read_ape_header;
|
||||||
#[cfg(feature = "ape")]
|
#[cfg(feature = "ape")]
|
||||||
use crate::ape::tag::read::read_ape_tag;
|
use crate::ape::tag::read::read_ape_tag;
|
||||||
use crate::ape::tag::read_ape_header;
|
|
||||||
use crate::error::{FileDecodingError, Result};
|
use crate::error::{FileDecodingError, Result};
|
||||||
#[cfg(feature = "id3v2")]
|
#[cfg(feature = "id3v2")]
|
||||||
use crate::id3::v2::read::parse_id3v2;
|
use crate::id3::v2::read::parse_id3v2;
|
||||||
|
|
|
@ -4,29 +4,31 @@
|
||||||
//!
|
//!
|
||||||
//! The only supported tag format is [`Ilst`].
|
//! The only supported tag format is [`Ilst`].
|
||||||
mod atom_info;
|
mod atom_info;
|
||||||
#[cfg(feature = "mp4_ilst")]
|
|
||||||
pub(crate) mod ilst;
|
|
||||||
mod moov;
|
mod moov;
|
||||||
mod properties;
|
mod properties;
|
||||||
mod read;
|
mod read;
|
||||||
mod trak;
|
mod trak;
|
||||||
|
|
||||||
pub use crate::mp4::properties::{Mp4Codec, Mp4Properties};
|
use crate::error::Result;
|
||||||
#[cfg(feature = "mp4_ilst")]
|
|
||||||
pub use crate::mp4::{
|
|
||||||
atom_info::AtomIdent,
|
|
||||||
ilst::{
|
|
||||||
atom::{Atom, AtomData},
|
|
||||||
Ilst,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::tag_utils::tag_methods;
|
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
use crate::{FileProperties, Result, TagType};
|
use crate::types::properties::FileProperties;
|
||||||
|
use crate::types::tag::TagType;
|
||||||
|
|
||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
|
||||||
|
crate::macros::feature_locked! {
|
||||||
|
#![cfg(feature = "mp4_ilst")]
|
||||||
|
pub(crate) mod ilst;
|
||||||
|
|
||||||
|
pub use atom_info::AtomIdent;
|
||||||
|
pub use ilst::atom::{Atom, AtomData};
|
||||||
|
pub use ilst::Ilst;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use crate::mp4::properties::{Mp4Codec, Mp4Properties};
|
||||||
|
|
||||||
/// An MP4 file
|
/// An MP4 file
|
||||||
pub struct Mp4File {
|
pub struct Mp4File {
|
||||||
/// The file format from ftyp's "major brand" (Ex. "M4A ")
|
/// The file format from ftyp's "major brand" (Ex. "M4A ")
|
||||||
|
@ -97,8 +99,8 @@ impl Mp4File {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mp4File {
|
impl Mp4File {
|
||||||
tag_methods! {
|
crate::macros::tag_methods! {
|
||||||
#[cfg(feature = "mp4_ilst")];
|
#[cfg(feature = "mp4_ilst")]
|
||||||
ilst, Ilst
|
ilst, Ilst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ pub(crate) mod write;
|
||||||
#[cfg(feature = "vorbis_comments")]
|
#[cfg(feature = "vorbis_comments")]
|
||||||
use super::tag::VorbisComments;
|
use super::tag::VorbisComments;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::tag_utils::tag_methods;
|
|
||||||
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
use crate::types::file::{AudioFile, FileType, TaggedFile};
|
||||||
use crate::types::properties::FileProperties;
|
use crate::types::properties::FileProperties;
|
||||||
use crate::types::tag::TagType;
|
use crate::types::tag::TagType;
|
||||||
|
@ -73,8 +72,8 @@ impl AudioFile for FlacFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlacFile {
|
impl FlacFile {
|
||||||
tag_methods! {
|
crate::macros::tag_methods! {
|
||||||
#[cfg(feature = "vorbis_comments")];
|
#[cfg(feature = "vorbis_comments")]
|
||||||
vorbis_comments, VorbisComments
|
vorbis_comments, VorbisComments
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,32 +8,33 @@ pub(crate) mod flac;
|
||||||
pub(crate) mod opus;
|
pub(crate) mod opus;
|
||||||
pub(crate) mod read;
|
pub(crate) mod read;
|
||||||
pub(crate) mod speex;
|
pub(crate) mod speex;
|
||||||
#[cfg(feature = "vorbis_comments")]
|
|
||||||
pub(crate) mod tag;
|
|
||||||
pub(crate) mod vorbis;
|
pub(crate) mod vorbis;
|
||||||
#[cfg(feature = "vorbis_comments")]
|
|
||||||
pub(crate) mod write;
|
|
||||||
|
|
||||||
use crate::error::{FileDecodingError, Result};
|
use crate::error::{FileDecodingError, Result};
|
||||||
use crate::types::file::FileType;
|
use crate::types::file::FileType;
|
||||||
|
|
||||||
// Exports
|
|
||||||
|
|
||||||
#[cfg(feature = "vorbis_comments")]
|
|
||||||
pub use crate::ogg::tag::VorbisComments;
|
|
||||||
|
|
||||||
pub use crate::ogg::flac::FlacFile;
|
|
||||||
pub use crate::ogg::opus::properties::OpusProperties;
|
|
||||||
pub use crate::ogg::opus::OpusFile;
|
|
||||||
pub use crate::ogg::speex::properties::SpeexProperties;
|
|
||||||
pub use crate::ogg::speex::SpeexFile;
|
|
||||||
pub use crate::ogg::vorbis::properties::VorbisProperties;
|
|
||||||
pub use crate::ogg::vorbis::VorbisFile;
|
|
||||||
|
|
||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
use ogg_pager::Page;
|
use ogg_pager::Page;
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
|
||||||
|
crate::macros::feature_locked! {
|
||||||
|
#![cfg(feature = "vorbis_comments")]
|
||||||
|
pub(crate) mod write;
|
||||||
|
|
||||||
|
pub(crate) mod tag;
|
||||||
|
pub use tag::VorbisComments;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use flac::FlacFile;
|
||||||
|
pub use opus::properties::OpusProperties;
|
||||||
|
pub use opus::OpusFile;
|
||||||
|
pub use speex::properties::SpeexProperties;
|
||||||
|
pub use speex::SpeexFile;
|
||||||
|
pub use vorbis::properties::VorbisProperties;
|
||||||
|
pub use vorbis::VorbisFile;
|
||||||
|
|
||||||
pub(self) fn verify_signature(page: &Page, sig: &[u8]) -> Result<()> {
|
pub(self) fn verify_signature(page: &Page, sig: &[u8]) -> Result<()> {
|
||||||
let sig_len = sig.len();
|
let sig_len = sig.len();
|
||||||
|
|
||||||
|
|
|
@ -75,40 +75,6 @@ pub(crate) fn dump_tag<W: Write>(tag: &Tag, writer: &mut W) -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! tag_methods {
|
|
||||||
(
|
|
||||||
$(
|
|
||||||
$(#[$attr:meta])?;
|
|
||||||
$name:ident,
|
|
||||||
$ty:ty
|
|
||||||
);*
|
|
||||||
) => {
|
|
||||||
paste::paste! {
|
|
||||||
$(
|
|
||||||
$(#[$attr])?
|
|
||||||
#[doc = "Gets the [`" $ty "`] if it exists"]
|
|
||||||
pub fn $name(&self) -> Option<&$ty> {
|
|
||||||
self.$name.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
$(#[$attr])?
|
|
||||||
#[doc = "Gets a mutable reference to the [`" $ty "`] if it exists"]
|
|
||||||
pub fn [<$name _mut>](&mut self) -> Option<&mut $ty> {
|
|
||||||
self.$name.as_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
$(#[$attr])?
|
|
||||||
#[doc = "Removes the [`" $ty "`]"]
|
|
||||||
pub fn [<remove_ $name>](&mut self) {
|
|
||||||
self.$name = None
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) use tag_methods;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
// Used for tag conversion tests
|
// Used for tag conversion tests
|
||||||
pub(crate) mod test_utils {
|
pub(crate) mod test_utils {
|
||||||
|
|
|
@ -110,7 +110,7 @@ impl MimeType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The picture type
|
/// The picture type, according to ID3v2 APIC
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
pub enum PictureType {
|
pub enum PictureType {
|
||||||
|
@ -141,8 +141,8 @@ pub enum PictureType {
|
||||||
impl PictureType {
|
impl PictureType {
|
||||||
// ID3/OGG specific methods
|
// ID3/OGG specific methods
|
||||||
|
|
||||||
/// Get a u8 from a `PictureType` according to ID3v2 APIC
|
|
||||||
#[cfg(any(feature = "id3v2", feature = "vorbis_comments"))]
|
#[cfg(any(feature = "id3v2", feature = "vorbis_comments"))]
|
||||||
|
/// 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 {
|
||||||
Self::Other => 0,
|
Self::Other => 0,
|
||||||
|
@ -170,8 +170,8 @@ impl PictureType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a `PictureType` from a u8 according to ID3v2 APIC
|
|
||||||
#[cfg(any(feature = "id3v2", feature = "vorbis_comments"))]
|
#[cfg(any(feature = "id3v2", feature = "vorbis_comments"))]
|
||||||
|
/// Get a `PictureType` from a u8 according to ID3v2 APIC
|
||||||
pub fn from_u8(bytes: u8) -> Self {
|
pub fn from_u8(bytes: u8) -> Self {
|
||||||
match bytes {
|
match bytes {
|
||||||
0 => Self::Other,
|
0 => Self::Other,
|
||||||
|
@ -201,8 +201,8 @@ impl PictureType {
|
||||||
|
|
||||||
// APE specific methods
|
// APE specific methods
|
||||||
|
|
||||||
/// Get an APE item key from a `PictureType`
|
|
||||||
#[cfg(feature = "ape")]
|
#[cfg(feature = "ape")]
|
||||||
|
/// Get an APE item key from a `PictureType`
|
||||||
pub fn as_ape_key(&self) -> Option<&str> {
|
pub fn as_ape_key(&self) -> Option<&str> {
|
||||||
match self {
|
match self {
|
||||||
Self::Other => Some("Cover Art (Other)"),
|
Self::Other => Some("Cover Art (Other)"),
|
||||||
|
@ -230,8 +230,8 @@ impl PictureType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a `PictureType` from an APE item key
|
|
||||||
#[cfg(feature = "ape")]
|
#[cfg(feature = "ape")]
|
||||||
|
/// Get a `PictureType` from an APE item key
|
||||||
pub fn from_ape_key(key: &str) -> Self {
|
pub fn from_ape_key(key: &str) -> Self {
|
||||||
match key {
|
match key {
|
||||||
"Cover Art (Other)" => Self::Other,
|
"Cover Art (Other)" => Self::Other,
|
||||||
|
|
Loading…
Reference in a new issue