mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2024-11-10 06:34:18 +00:00
MP4: Create DataType
enum, replacing constants
This commit is contained in:
parent
637052978b
commit
9eb35ae1b9
6 changed files with 336 additions and 95 deletions
|
@ -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<u8>) -> 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<u8>,
|
||||
},
|
||||
}
|
||||
|
||||
/// The parental advisory rating
|
||||
///
|
||||
/// See also:
|
||||
/// <https://docs.mp3tag.de/mapping/#itunesadvisory>
|
||||
/// <https://exiftool.org/TagNames/QuickTime.html>
|
||||
#[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<u8> for AdvisoryRating {
|
||||
type Error = u8;
|
||||
|
||||
fn try_from(input: u8) -> std::result::Result<Self, Self::Error> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
200
lofty/src/mp4/ilst/data_type.rs
Normal file
200
lofty/src/mp4/ilst/data_type.rs
Normal file
|
@ -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<u32> 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<DataType> 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<MimeType> 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;
|
||||
}
|
|
@ -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<u16> {
|
||||
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(),
|
||||
},
|
||||
);
|
||||
|
|
|
@ -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<R>(
|
|||
reader: &mut AtomReader<R>,
|
||||
parsing_mode: ParsingMode,
|
||||
atom_info: &AtomInfo,
|
||||
) -> Result<Option<Vec<(u32, Vec<u8>)>>>
|
||||
) -> Result<Option<Vec<(DataType, Vec<u8>)>>>
|
||||
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<R>(
|
||||
reader: &mut AtomReader<R>,
|
||||
parsing_mode: ParsingMode,
|
||||
) -> Result<Option<DataType>>
|
||||
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<u32> {
|
||||
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<u8>) -> Result<AtomData> {
|
||||
fn interpret_atom_content(flags: DataType, content: Vec<u8>) -> Result<AtomData> {
|
||||
// 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,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue