From 9eb35ae1b9eda98e5ee5ee1f47db12eb9e711959 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Sat, 14 Sep 2024 16:15:06 -0400 Subject: [PATCH] MP4: Create `DataType` enum, replacing constants --- lofty/src/mp4/ilst/atom.rs | 86 +++++++------- lofty/src/mp4/ilst/data_type.rs | 200 ++++++++++++++++++++++++++++++++ lofty/src/mp4/ilst/mod.rs | 32 +++-- lofty/src/mp4/ilst/read.rs | 75 ++++++++---- lofty/src/mp4/ilst/write.rs | 35 +++--- lofty/src/mp4/mod.rs | 3 +- 6 files changed, 336 insertions(+), 95 deletions(-) create mode 100644 lofty/src/mp4/ilst/data_type.rs diff --git a/lofty/src/mp4/ilst/atom.rs b/lofty/src/mp4/ilst/atom.rs index 4f0bccf7..00562cbe 100644 --- a/lofty/src/mp4/ilst/atom.rs +++ b/lofty/src/mp4/ilst/atom.rs @@ -1,5 +1,6 @@ use crate::error::Result; use crate::macros::err; +use crate::mp4::ilst::data_type::DataType; use crate::mp4::AtomIdent; use crate::picture::Picture; @@ -213,7 +214,10 @@ impl<'a> Atom<'a> { pub(crate) fn unknown_implicit(ident: AtomIdent<'_>, data: Vec) -> Self { Self { ident: ident.into_owned(), - data: AtomDataStorage::Single(AtomData::Unknown { code: 0, data }), + data: AtomDataStorage::Single(AtomData::Unknown { + code: DataType::Reserved, + data, + }), } } @@ -247,8 +251,7 @@ impl Debug for Atom<'_> { /// NOTES: /// /// * This only covers the most common data types. -/// See the list of [well-known data types](https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW34) -/// for codes. +/// See the list of [DataType] for all known types. /// * There are only two variants for integers, which /// will come from codes `21` and `22`. All other integer /// types will be stored as [`AtomData::Unknown`], refer @@ -290,51 +293,52 @@ pub enum AtomData { /// variant. Unknown { /// The code, or type of the item - code: u32, + code: DataType, /// The binary data of the atom data: Vec, }, } -/// The parental advisory rating -/// -/// See also: -/// -/// -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum AdvisoryRating { - /// *Inoffensive*/*None* (0) - Inoffensive, - /// *Explicit* (1 or 4) +impl AtomData { + /// Get the [`DataType`] of the atom /// - /// In the past Apple used the value 4 for explicit content - /// that has later been replaced by 1. Both values are considered - /// as valid when reading but only the newer value 1 is written. - Explicit, - /// *Clean*/*Edited* (2) - Clean, -} - -impl AdvisoryRating { - /// Returns the rating as it appears in the `rtng` atom - pub fn as_u8(&self) -> u8 { + /// Note that for [`AtomData::Picture`], the type is determined by the picture's MIME type. + /// If the MIME type is unknown (or unset), the data type will be [`DataType::Reserved`]. + /// + /// # Examples + /// + /// ```rust + /// use lofty::mp4::{AtomData, DataType}; + /// use lofty::picture::{MimeType, Picture, PictureType}; + /// + /// let data = AtomData::UTF8(String::from("foo")); + /// assert_eq!(data.data_type(), DataType::Utf8); + /// + /// let data = AtomData::SignedInteger(42); + /// assert_eq!(data.data_type(), DataType::BeSignedInteger); + /// + /// let data = AtomData::Picture(Picture::new_unchecked( + /// PictureType::CoverFront, + /// Some(MimeType::Jpeg), + /// None, + /// Vec::new(), + /// )); + /// assert_eq!(data.data_type(), DataType::Jpeg); + /// ``` + pub fn data_type(&self) -> DataType { match self { - AdvisoryRating::Inoffensive => 0, - AdvisoryRating::Explicit => 1, - AdvisoryRating::Clean => 2, - } - } -} - -impl TryFrom for AdvisoryRating { - type Error = u8; - - fn try_from(input: u8) -> std::result::Result { - match input { - 0 => Ok(Self::Inoffensive), - 1 | 4 => Ok(Self::Explicit), - 2 => Ok(Self::Clean), - value => Err(value), + AtomData::UTF8(_) => DataType::Utf8, + AtomData::UTF16(_) => DataType::Utf16, + AtomData::SignedInteger(_) | AtomData::Bool(_) => DataType::BeSignedInteger, + AtomData::UnsignedInteger(_) => DataType::BeUnsignedInteger, + AtomData::Picture(p) => { + let Some(mime) = p.mime_type() else { + return DataType::Reserved; + }; + + DataType::from(mime) + }, + AtomData::Unknown { code, .. } => *code, } } } diff --git a/lofty/src/mp4/ilst/data_type.rs b/lofty/src/mp4/ilst/data_type.rs new file mode 100644 index 00000000..d70aabf0 --- /dev/null +++ b/lofty/src/mp4/ilst/data_type.rs @@ -0,0 +1,200 @@ +use crate::picture::MimeType; + +/// The [well known] basic data types +/// +/// This should cover all the data types you'll encounter in an MP4 file. +/// +/// [well known]: https://developer.apple.com/documentation/quicktime-file-format/well-known_types +// OLD LINKS: +// * https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW35 +#[repr(u32)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum DataType { + /// Reserved for use where no type needs to be indicated + Reserved = 0, + /// UTF-8 string without any count or NULL terminator + Utf8 = 1, + /// A big-endian UTF-16 string + Utf16 = 2, + /// Deprecated unless it is needed for special Japanese characters + SJis = 3, + /// The UTF-8 variant storage of a string for sorting only + Utf8Sort = 4, + /// The UTF-16 variant storage of a string for sorting only + Utf16Sort = 5, + /// **DEPRECATED** A GIF image + Gif = 12, + /// A JPEG in a JFIF wrapper + Jpeg = 13, + /// A PNG in a PNG wrapper + Png = 14, + /// A big-endian signed integer in 1,2,3 or 4 bytes + BeSignedInteger = 21, + /// A big-endian unsigned integer in 1,2,3 or 4 bytes; size of value determines integer size + BeUnsignedInteger = 22, + /// A big-endian 32-bit floating point value (IEEE754) + BeFloat32 = 23, + /// A big-endian 64-bit floating point value (IEEE754) + BeFloat64 = 24, + /// Windows bitmap format graphics + Bmp = 27, + /// A QuickTime metadata atom + QuicktimeMetadata = 28, + /// An 8-bit signed integer + Signed8BitInteger = 65, + /// A big-endian 16-bit signed integer + Be16BitSignedInteger = 66, + /// A big-endian 32-bit signed integer + Be32BitSignedInteger = 67, + /// A block of data representing a two dimensional (2D) point with 32-bit big-endian floating point x and y coordinates. It has the structure: + /// + /// ```c + /// struct { + /// BEFloat32 x; + /// BEFloat32 y; + /// } + /// ``` + BePointF32 = 70, + /// A block of data representing 2D dimensions with 32-bit big-endian floating point width and height. It has the structure: + /// + /// ```c + /// struct { + /// BEFloat32 width; + /// BEFloat32 height; + /// } + /// ``` + BeDimensionsF32 = 71, + /// A block of data representing a 2D rectangle with 32-bit big-endian floating point x and y coordinates and a 32-bit big-endian floating point width and height size. It has the structure: + /// + /// ```c + /// struct { + /// BEFloat32 x; + /// BEFloat32 y; + /// BEFloat32 width; + /// BEFloat32 height; + /// } + /// ``` + /// + /// or the equivalent structure: + /// + /// ```c + /// struct { + /// PointF32 origin; + /// DimensionsF32 size; + /// } + /// ``` + BeRectF32 = 72, + /// A big-endian 64-bit signed integer + Be64BitSignedInteger = 74, + /// An 8-bit unsigned integer + Unsigned8BitInteger = 75, + /// A big-endian 16-bit unsigned integer + Be16BitUnsignedInteger = 76, + /// A big-endian 32-bit unsigned integer + Be32BitUnsignedInteger = 77, + /// A big-endian 64-bit unsigned integer + Be64BitUnsignedInteger = 78, + /// A block of data representing a 3x3 transformation matrix. It has the structure: + /// + /// ```c + /// struct { + /// BEFloat64 matrix[3][3]; + /// } + /// ``` + AffineTransformF64 = 79, + /// Some other data type + Other(u32), +} + +impl From for DataType { + fn from(value: u32) -> Self { + match value { + 0 => DataType::Reserved, + 1 => DataType::Utf8, + 2 => DataType::Utf16, + 3 => DataType::SJis, + 4 => DataType::Utf8Sort, + 5 => DataType::Utf16Sort, + 12 => DataType::Gif, + 13 => DataType::Jpeg, + 14 => DataType::Png, + 21 => DataType::BeSignedInteger, + 22 => DataType::BeUnsignedInteger, + 23 => DataType::BeFloat32, + 24 => DataType::BeFloat64, + 27 => DataType::Bmp, + 28 => DataType::QuicktimeMetadata, + 65 => DataType::Signed8BitInteger, + 66 => DataType::Be16BitSignedInteger, + 67 => DataType::Be32BitSignedInteger, + 70 => DataType::BePointF32, + 71 => DataType::BeDimensionsF32, + 72 => DataType::BeRectF32, + 74 => DataType::Be64BitSignedInteger, + 75 => DataType::Unsigned8BitInteger, + 76 => DataType::Be16BitUnsignedInteger, + 77 => DataType::Be32BitUnsignedInteger, + 78 => DataType::Be64BitUnsignedInteger, + 79 => DataType::AffineTransformF64, + other => DataType::Other(other), + } + } +} + +impl From for u32 { + fn from(value: DataType) -> Self { + match value { + DataType::Reserved => 0, + DataType::Utf8 => 1, + DataType::Utf16 => 2, + DataType::SJis => 3, + DataType::Utf8Sort => 4, + DataType::Utf16Sort => 5, + DataType::Gif => 12, + DataType::Jpeg => 13, + DataType::Png => 14, + DataType::BeSignedInteger => 21, + DataType::BeUnsignedInteger => 22, + DataType::BeFloat32 => 23, + DataType::BeFloat64 => 24, + DataType::Bmp => 27, + DataType::QuicktimeMetadata => 28, + DataType::Signed8BitInteger => 65, + DataType::Be16BitSignedInteger => 66, + DataType::Be32BitSignedInteger => 67, + DataType::BePointF32 => 70, + DataType::BeDimensionsF32 => 71, + DataType::BeRectF32 => 72, + DataType::Be64BitSignedInteger => 74, + DataType::Unsigned8BitInteger => 75, + DataType::Be16BitUnsignedInteger => 76, + DataType::Be32BitUnsignedInteger => 77, + DataType::Be64BitUnsignedInteger => 78, + DataType::AffineTransformF64 => 79, + DataType::Other(other) => other, + } + } +} + +impl From for DataType { + fn from(value: MimeType) -> Self { + DataType::from(&value) + } +} + +impl From<&MimeType> for DataType { + fn from(value: &MimeType) -> Self { + match value { + MimeType::Gif => DataType::Gif, + MimeType::Jpeg => DataType::Jpeg, + MimeType::Png => DataType::Png, + MimeType::Bmp => DataType::Bmp, + _ => DataType::Reserved, + } + } +} + +impl DataType { + /// A data type can only occupy 24 bits + pub const MAX: u32 = 16_777_215; +} diff --git a/lofty/src/mp4/ilst/mod.rs b/lofty/src/mp4/ilst/mod.rs index ce42f328..3f1f4fe1 100644 --- a/lofty/src/mp4/ilst/mod.rs +++ b/lofty/src/mp4/ilst/mod.rs @@ -1,6 +1,7 @@ pub(super) mod advisory_rating; pub(super) mod atom; pub(super) mod constants; +pub(super) mod data_type; pub(super) mod read; mod r#ref; pub(crate) mod write; @@ -16,8 +17,9 @@ use crate::tag::{ }; use crate::util::flag_item; use crate::util::io::{FileLike, Length, Truncate}; -use atom::{AdvisoryRating, Atom, AtomData}; use advisory_rating::AdvisoryRating; +use atom::{Atom, AtomData}; +use data_type::DataType; use std::borrow::Cow; use std::io::Write; @@ -374,7 +376,10 @@ impl Ilst { fn extract_number(&self, fourcc: [u8; 4], expected_size: usize) -> Option { if let Some(atom) = self.get(&AtomIdent::Fourcc(fourcc)) { match atom.data().next() { - Some(AtomData::Unknown { code: 0, data }) if data.len() >= expected_size => { + Some(AtomData::Unknown { + code: DataType::Reserved, + data, + }) if data.len() >= expected_size => { return Some(u16::from_be_bytes([ data[expected_size - 2], data[expected_size - 1], @@ -603,7 +608,10 @@ impl SplitTag for Ilst { ItemValue::Text(text) }, // We have to special case track/disc numbers since they are stored together - AtomData::Unknown { code: 0, data } if Vec::len(data) >= 6 => { + AtomData::Unknown { + code: DataType::Reserved, + data, + } if Vec::len(data) >= 6 => { if let AtomIdent::Fourcc(ref fourcc) = ident { match fourcc { b"trkn" => { @@ -686,7 +694,7 @@ impl MergeTag for SplitTagRemainder { tag.atoms.push(Atom { ident: AtomIdent::Fourcc(ident), data: AtomDataStorage::Single(AtomData::Unknown { - code: 0, + code: DataType::Reserved, data: vec![0, 0, current[0], current[1], total[0], total[1], 0, 0], }), }) @@ -802,13 +810,13 @@ mod tests { use crate::mp4::ilst::atom::AtomDataStorage; use crate::mp4::ilst::TITLE; use crate::mp4::read::AtomReader; - use crate::mp4::{AdvisoryRating, Atom, AtomData, AtomIdent, Ilst, Mp4File}; + use crate::mp4::{AdvisoryRating, Atom, AtomData, AtomIdent, DataType, Ilst, Mp4File}; + use crate::picture::{MimeType, Picture, PictureType}; use crate::prelude::*; use crate::tag::utils::test_utils; use crate::tag::utils::test_utils::read_path; use crate::tag::{ItemValue, Tag, TagItem, TagType}; - use crate::picture::{MimeType, Picture, PictureType}; use std::io::{Cursor, Read as _, Seek as _, Write as _}; fn read_ilst(path: &str, parse_mode: ParsingMode) -> Ilst { @@ -853,7 +861,7 @@ mod tests { expected_tag.insert(Atom::new( AtomIdent::Fourcc(*b"trkn"), AtomData::Unknown { - code: 0, + code: DataType::Reserved, data: vec![0, 0, 0, 1, 0, 0, 0, 0], }, )); @@ -862,7 +870,7 @@ mod tests { expected_tag.insert(Atom::new( AtomIdent::Fourcc(*b"disk"), AtomData::Unknown { - code: 0, + code: DataType::Reserved, data: vec![0, 0, 0, 1, 0, 2], }, )); @@ -997,7 +1005,7 @@ mod tests { &ilst, *b"trkn", &AtomData::Unknown { - code: 0, + code: DataType::Reserved, data: vec![0, 0, 0, 1, 0, 0, 0, 0], }, ); @@ -1005,7 +1013,7 @@ mod tests { &ilst, *b"disk", &AtomData::Unknown { - code: 0, + code: DataType::Reserved, data: vec![0, 0, 0, 1, 0, 2, 0, 0], }, ) @@ -1024,7 +1032,7 @@ mod tests { &ilst, *b"plID", &AtomData::Unknown { - code: 21, + code: DataType::BeSignedInteger, data: 88888_u64.to_be_bytes().to_vec(), }, ) @@ -1321,7 +1329,7 @@ mod tests { let atom = Atom::new( AtomIdent::Fourcc(*b"SMTH"), AtomData::Unknown { - code: 0, + code: DataType::Reserved, data: b"Meaningless Data".to_vec(), }, ); diff --git a/lofty/src/mp4/ilst/read.rs b/lofty/src/mp4/ilst/read.rs index e44e2c37..84beb70d 100644 --- a/lofty/src/mp4/ilst/read.rs +++ b/lofty/src/mp4/ilst/read.rs @@ -1,12 +1,11 @@ -use super::constants::{ - BE_SIGNED_INTEGER, BE_UNSIGNED_INTEGER, BMP, JPEG, PNG, RESERVED, UTF16, UTF8, -}; +use super::constants::WELL_KNOWN_TYPE_SET; +use super::data_type::DataType; use super::{Atom, AtomData, AtomIdent, Ilst}; use crate::config::{ParseOptions, ParsingMode}; use crate::error::{LoftyError, Result}; use crate::id3::v1::constants::GENRES; use crate::macros::{err, try_vec}; -use crate::mp4::atom_info::AtomInfo; +use crate::mp4::atom_info::{AtomInfo, ATOM_HEADER_LEN}; use crate::mp4::ilst::atom::AtomDataStorage; use crate::mp4::read::{skip_unneeded, AtomReader}; use crate::picture::{MimeType, Picture, PictureType}; @@ -204,7 +203,7 @@ fn parse_data_inner( reader: &mut AtomReader, parsing_mode: ParsingMode, atom_info: &AtomInfo, -) -> Result)>>> +) -> Result)>>> where R: Read + Seek, { @@ -237,13 +236,14 @@ where break; } - // We don't care about the version - let _version = reader.read_u8()?; + let Some(data_type) = parse_type_indicator(reader, parsing_mode)? else { + log::warn!("Skipping atom with unknown type set"); + let remaining_atom_len = next_atom.len - (ATOM_HEADER_LEN + 1); - let mut flags = [0; 3]; - reader.read_exact(&mut flags)?; - - let flags = u32::from_be_bytes([0, flags[0], flags[1], flags[2]]); + reader.seek(SeekFrom::Current(remaining_atom_len as i64))?; + pos += remaining_atom_len; + continue; + }; // We don't care about the locale reader.seek(SeekFrom::Current(4))?; @@ -254,7 +254,7 @@ where if content_len > 0 { let mut content = try_vec![0; content_len]; reader.read_exact(&mut content)?; - ret.push((flags, content)); + ret.push((data_type, content)); } else { log::warn!("Skipping empty \"data\" atom"); } @@ -268,7 +268,9 @@ where "Skipping unexpected atom {actual_ident:?}, expected {expected_ident:?}", actual_ident = next_atom.ident, expected_ident = DATA_ATOM_IDENT - ) + ); + + reader.seek(SeekFrom::Current((next_atom.len - 16) as i64))?; }, }, } @@ -280,6 +282,29 @@ where Ok(ret) } +fn parse_type_indicator( + reader: &mut AtomReader, + parsing_mode: ParsingMode, +) -> Result> +where + R: Read + Seek, +{ + // The type indicator is formed of four bytes split between two fields. The first byte indicates + // the set of types from which the type is drawn. The second through fourth byte forms the second + // field and its interpretation depends upon the value in the first field. + + let type_set = reader.read_u8()?; + if type_set != WELL_KNOWN_TYPE_SET { + if parsing_mode == ParsingMode::Strict { + err!(BadAtom("Unknown type set in data atom")) + } + + return Ok(None); + } + + Ok(Some(DataType::from(reader.read_u24()?))) +} + fn parse_uint(bytes: &[u8]) -> Result { Ok(match bytes.len() { 1 => u32::from(bytes[0]), @@ -317,15 +342,15 @@ where let mut data = Vec::new(); let len = atom_data.len(); - for (flags, value) in atom_data { - let mime_type = match flags { + for (data_type, value) in atom_data { + let mime_type = match data_type { // Type 0 is implicit - RESERVED => None, + DataType::Reserved => None, // GIF is deprecated - 12 => Some(MimeType::Gif), - JPEG => Some(MimeType::Jpeg), - PNG => Some(MimeType::Png), - BMP => Some(MimeType::Bmp), + DataType::Gif => Some(MimeType::Gif), + DataType::Jpeg => Some(MimeType::Jpeg), + DataType::Png => Some(MimeType::Png), + DataType::Bmp => Some(MimeType::Bmp), _ => err!(BadAtom("\"covr\" atom has an unknown type")), }; @@ -357,13 +382,13 @@ where Ok(()) } -fn interpret_atom_content(flags: u32, content: Vec) -> Result { +fn interpret_atom_content(flags: DataType, content: Vec) -> Result { // https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW35 Ok(match flags { - UTF8 => AtomData::UTF8(utf8_decode(content)?), - UTF16 => AtomData::UTF16(utf16_decode_bytes(&content, u16::from_be_bytes)?), - BE_SIGNED_INTEGER => AtomData::SignedInteger(parse_int(&content)?), - BE_UNSIGNED_INTEGER => AtomData::UnsignedInteger(parse_uint(&content)?), + DataType::Utf8 => AtomData::UTF8(utf8_decode(content)?), + DataType::Utf16 => AtomData::UTF16(utf16_decode_bytes(&content, u16::from_be_bytes)?), + DataType::BeSignedInteger => AtomData::SignedInteger(parse_int(&content)?), + DataType::BeUnsignedInteger => AtomData::UnsignedInteger(parse_uint(&content)?), code => AtomData::Unknown { code, data: content, diff --git a/lofty/src/mp4/ilst/write.rs b/lofty/src/mp4/ilst/write.rs index 25791030..a671f738 100644 --- a/lofty/src/mp4/ilst/write.rs +++ b/lofty/src/mp4/ilst/write.rs @@ -1,3 +1,4 @@ +use super::data_type::DataType; use super::r#ref::IlstRef; use crate::config::{ParseOptions, WriteOptions}; use crate::error::{FileEncodingError, LoftyError, Result}; @@ -14,9 +15,6 @@ use crate::util::io::{FileLike, Length, Truncate}; use std::io::{Cursor, Seek, SeekFrom, Write}; -use crate::mp4::constants::{ - BE_SIGNED_INTEGER, BE_UNSIGNED_INTEGER, BMP, JPEG, PNG, RESERVED, UTF16, UTF8, -}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; // A "full" atom is a traditional length + identifier, followed by a version (1) and flags (3) @@ -678,8 +676,8 @@ where { for value in data { match value { - AtomData::UTF8(text) => write_data(UTF8, text.as_bytes(), writer)?, - AtomData::UTF16(text) => write_data(UTF16, text.as_bytes(), writer)?, + AtomData::UTF8(text) => write_data(DataType::Utf8, text.as_bytes(), writer)?, + AtomData::UTF16(text) => write_data(DataType::Utf16, text.as_bytes(), writer)?, AtomData::Picture(ref pic) => write_picture(pic, writer)?, AtomData::SignedInteger(int) => write_signed_int(*int, writer)?, AtomData::UnsignedInteger(uint) => write_unsigned_int(*uint, writer)?, @@ -692,7 +690,7 @@ where } fn write_signed_int(int: i32, writer: &mut AtomWriterCompanion<'_>) -> Result<()> { - write_int(BE_SIGNED_INTEGER, int.to_be_bytes(), 4, writer) + write_int(DataType::BeSignedInteger, int.to_be_bytes(), 4, writer) } fn bytes_to_occupy_uint(uint: u32) -> usize { @@ -710,7 +708,7 @@ fn bytes_to_occupy_uint(uint: u32) -> usize { fn write_unsigned_int(uint: u32, writer: &mut AtomWriterCompanion<'_>) -> Result<()> { let bytes_needed = bytes_to_occupy_uint(uint); write_int( - BE_UNSIGNED_INTEGER, + DataType::BeUnsignedInteger, uint.to_be_bytes(), bytes_needed, writer, @@ -718,7 +716,7 @@ fn write_unsigned_int(uint: u32, writer: &mut AtomWriterCompanion<'_>) -> Result } fn write_int( - flags: u32, + flags: DataType, bytes: [u8; 4], bytes_needed: usize, writer: &mut AtomWriterCompanion<'_>, @@ -728,18 +726,23 @@ fn write_int( } fn write_bool(b: bool, writer: &mut AtomWriterCompanion<'_>) -> Result<()> { - write_int(BE_SIGNED_INTEGER, i32::from(b).to_be_bytes(), 1, writer) + write_int( + DataType::BeSignedInteger, + i32::from(b).to_be_bytes(), + 1, + writer, + ) } fn write_picture(picture: &Picture, writer: &mut AtomWriterCompanion<'_>) -> Result<()> { match picture.mime_type { // GIF is deprecated - Some(MimeType::Gif) => write_data(12, &picture.data, writer), - Some(MimeType::Jpeg) => write_data(JPEG, &picture.data, writer), - Some(MimeType::Png) => write_data(PNG, &picture.data, writer), - Some(MimeType::Bmp) => write_data(BMP, &picture.data, writer), + Some(MimeType::Gif) => write_data(DataType::Gif, &picture.data, writer), + Some(MimeType::Jpeg) => write_data(DataType::Jpeg, &picture.data, writer), + Some(MimeType::Png) => write_data(DataType::Png, &picture.data, writer), + Some(MimeType::Bmp) => write_data(DataType::Bmp, &picture.data, writer), // We'll assume implicit (0) was the intended type - None => write_data(RESERVED, &picture.data, writer), + None => write_data(DataType::Reserved, &picture.data, writer), _ => Err(FileEncodingError::new( FileType::Mp4, "Attempted to write an unsupported picture format", @@ -748,8 +751,8 @@ fn write_picture(picture: &Picture, writer: &mut AtomWriterCompanion<'_>) -> Res } } -fn write_data(flags: u32, data: &[u8], writer: &mut AtomWriterCompanion<'_>) -> Result<()> { - if flags > 16_777_215 { +fn write_data(flags: DataType, data: &[u8], writer: &mut AtomWriterCompanion<'_>) -> Result<()> { + if u32::from(flags) > DataType::MAX { return Err(FileEncodingError::new( FileType::Mp4, "Attempted to write a code that cannot fit in 24 bits", diff --git a/lofty/src/mp4/mod.rs b/lofty/src/mp4/mod.rs index 7c77f7a2..6f35cb0b 100644 --- a/lofty/src/mp4/mod.rs +++ b/lofty/src/mp4/mod.rs @@ -23,8 +23,9 @@ pub mod constants { pub use crate::mp4::properties::{AudioObjectType, Mp4Codec, Mp4Properties}; pub use atom_info::AtomIdent; -pub use ilst::atom::{AdvisoryRating, Atom, AtomData}; pub use ilst::advisory_rating::AdvisoryRating; +pub use ilst::atom::{Atom, AtomData}; +pub use ilst::data_type::DataType; pub use ilst::Ilst; pub(crate) use properties::SAMPLE_RATES;