diff --git a/musikr/src/main/jni/shim/mp4_shim.cpp b/musikr/src/main/jni/shim/mp4_shim.cpp index a01add652..ae16a98c8 100644 --- a/musikr/src/main/jni/shim/mp4_shim.cpp +++ b/musikr/src/main/jni/shim/mp4_shim.cpp @@ -24,4 +24,62 @@ namespace taglib_shim { return entries; } + + IntPair::IntPair(int first, int second) + : first_(first), second_(second) {} + + int IntPair::first() const { + return first_; + } + + int IntPair::second() const { + return second_; + } + + CoverArt::CoverArt(TagLib::MP4::CoverArt::Format format, const TagLib::ByteVector& data) + : art_(format, data) {} + + uint32_t CoverArt::format() const { + return static_cast(art_.format()); + } + + std::unique_ptr CoverArt::data() const { + return std::make_unique(art_.data()); + } + + CoverArtList::CoverArtList(const TagLib::MP4::CoverArtList& list) + : list_(list) {} + + std::unique_ptr> CoverArtList::to_vector() const { + auto vec = std::make_unique>(); + for (const auto& item : list_) { + vec->emplace_back(item.format(), item.data()); + } + return vec; + } + + unsigned int Item_type(const TagLib::MP4::Item& item) { + return static_cast(item.type()); + } + + std::unique_ptr Item_toIntPair(const TagLib::MP4::Item& item) { + auto pair = item.toIntPair(); + return std::make_unique(pair.first, pair.second); + } + + std::unique_ptr Item_toStringList(const TagLib::MP4::Item& item) { + return std::make_unique(item.toStringList()); + } + + std::unique_ptr Item_toByteVectorList(const TagLib::MP4::Item& item) { + return std::make_unique(item.toByteVectorList()); + } + + std::unique_ptr Item_toCoverArtList(const TagLib::MP4::Item& item) { + return std::make_unique(item.toCoverArtList()); + } + + int64_t Item_toLongLong(const TagLib::MP4::Item& item) { + return item.toLongLong(); + } } \ No newline at end of file diff --git a/musikr/src/main/jni/shim/mp4_shim.hpp b/musikr/src/main/jni/shim/mp4_shim.hpp index e4c00565c..da73a92f6 100644 --- a/musikr/src/main/jni/shim/mp4_shim.hpp +++ b/musikr/src/main/jni/shim/mp4_shim.hpp @@ -19,4 +19,41 @@ namespace taglib_shim { }; std::unique_ptr> ItemMap_to_entries(const TagLib::MP4::ItemMap& map); + + class IntPair { + public: + IntPair(int first, int second); + int first() const; + int second() const; + + private: + int first_; + int second_; + }; + + class CoverArt { + public: + CoverArt(TagLib::MP4::CoverArt::Format format, const TagLib::ByteVector& data); + uint32_t format() const; + std::unique_ptr data() const; + + private: + TagLib::MP4::CoverArt art_; + }; + + class CoverArtList { + public: + CoverArtList(const TagLib::MP4::CoverArtList& list); + std::unique_ptr> to_vector() const; + + private: + TagLib::MP4::CoverArtList list_; + }; + + unsigned int Item_type(const TagLib::MP4::Item& item); + std::unique_ptr Item_toIntPair(const TagLib::MP4::Item& item); + std::unique_ptr Item_toStringList(const TagLib::MP4::Item& item); + std::unique_ptr Item_toByteVectorList(const TagLib::MP4::Item& item); + std::unique_ptr Item_toCoverArtList(const TagLib::MP4::Item& item); + int64_t Item_toLongLong(const TagLib::MP4::Item& item); } \ No newline at end of file diff --git a/musikr/src/main/jni/shim/tk_shim.cpp b/musikr/src/main/jni/shim/tk_shim.cpp index e5ec3d389..250c9c530 100644 --- a/musikr/src/main/jni/shim/tk_shim.cpp +++ b/musikr/src/main/jni/shim/tk_shim.cpp @@ -32,4 +32,14 @@ namespace taglib_shim } return result; } + + std::unique_ptr> ByteVectorList_to_vector(const TagLib::ByteVectorList &list) + { + std::unique_ptr> result = std::make_unique>(); + for (const auto &vec : list) + { + result->push_back(vec); + } + return result; + } } diff --git a/musikr/src/main/jni/shim/tk_shim.hpp b/musikr/src/main/jni/shim/tk_shim.hpp index 5f59ccd0a..3fe1bb924 100644 --- a/musikr/src/main/jni/shim/tk_shim.hpp +++ b/musikr/src/main/jni/shim/tk_shim.hpp @@ -30,4 +30,6 @@ namespace taglib_shim std::unique_ptr> SimplePropertyMap_to_vector(const TagLib::SimplePropertyMap &map); std::unique_ptr> StringList_to_vector(const TagLib::StringList &list); + + std::unique_ptr> ByteVectorList_to_vector(const TagLib::ByteVectorList &list); } \ No newline at end of file diff --git a/musikr/src/main/jni/src/taglib/bridge.rs b/musikr/src/main/jni/src/taglib/bridge.rs index 5d26f28a8..284b04002 100644 --- a/musikr/src/main/jni/src/taglib/bridge.rs +++ b/musikr/src/main/jni/src/taglib/bridge.rs @@ -220,6 +220,12 @@ mod bridge_impl { string_list: Pin<&CPPStringList>, ) -> UniquePtr>; + #[namespace = "TagLib"] + #[cxx_name = "ByteVectorList"] + type CPPByteVectorList; + #[namespace = "taglib_shim"] + fn ByteVectorList_to_vector(list: Pin<&CPPByteVectorList>) -> UniquePtr>; + #[namespace = "TagLib"] #[cxx_name = "ByteVector"] type CPPByteVector; @@ -251,13 +257,78 @@ mod bridge_impl { #[namespace = "taglib_shim"] #[cxx_name = "ItemMapEntry"] type CPPItemMapEntry; - fn key(self: Pin<&CPPItemMapEntry>) -> &CPPString; - fn value(self: Pin<&CPPItemMapEntry>) -> &CPPMP4Item; + fn key<'slf, 'file_ref>(self: Pin<&'slf CPPItemMapEntry>) -> &'file_ref CPPString; + fn value<'slf, 'file_ref>(self: Pin<&'slf CPPItemMapEntry>) -> &'file_ref CPPMP4Item; #[namespace = "TagLib::MP4"] #[cxx_name = "Item"] type CPPMP4Item; + fn isValid(self: Pin<&CPPMP4Item>) -> bool; + fn toBool(self: Pin<&CPPMP4Item>) -> bool; + fn toInt(self: Pin<&CPPMP4Item>) -> i32; + fn toByte(self: Pin<&CPPMP4Item>) -> u8; + fn toUInt(self: Pin<&CPPMP4Item>) -> u32; + fn Item_type(item: Pin<&CPPMP4Item>) -> u32; + #[namespace = "taglib_shim"] + fn Item_toIntPair(item: Pin<&CPPMP4Item>) -> UniquePtr; + #[namespace = "taglib_shim"] + fn Item_toStringList(item: Pin<&CPPMP4Item>) -> UniquePtr; + #[namespace = "taglib_shim"] + fn Item_toByteVectorList(item: Pin<&CPPMP4Item>) -> UniquePtr; + #[namespace = "taglib_shim"] + fn Item_toCoverArtList(item: Pin<&CPPMP4Item>) -> UniquePtr; + #[namespace = "taglib_shim"] + fn Item_toLongLong(item: Pin<&CPPMP4Item>) -> i64; + + #[namespace = "taglib_shim"] + #[cxx_name = "IntPair"] + type CPPIntPair; + fn first(self: Pin<&CPPIntPair>) -> i32; + fn second(self: Pin<&CPPIntPair>) -> i32; + + #[namespace = "taglib_shim"] + #[cxx_name = "CoverArtList"] + type CPPCoverArtList; + fn to_vector(self: Pin<&CPPCoverArtList>) -> UniquePtr>; + + #[namespace = "taglib_shim"] + #[cxx_name = "CoverArt"] + type CPPCoverArt; + fn format(self: Pin<&CPPCoverArt>) -> u32; + fn data(self: Pin<&CPPCoverArt>) -> UniquePtr; + } +} + +#[repr(u8)] +pub enum MP4ItemType { + Void, + Bool, + Int, + IntPair, + Byte, + UInt, + LongLong, + StringList, + ByteVectorList, + CoverArtList, +} + +impl MP4ItemType { + pub fn from_u32(value: u32) -> Option { + match value { + 0 => Some(Self::Void), + 1 => Some(Self::Bool), + 2 => Some(Self::Int), + 3 => Some(Self::IntPair), + 4 => Some(Self::Byte), + 5 => Some(Self::UInt), + 6 => Some(Self::LongLong), + 7 => Some(Self::StringList), + 8 => Some(Self::ByteVectorList), + 9 => Some(Self::CoverArtList), + _ => None, + } } } diff --git a/musikr/src/main/jni/src/taglib/iostream.rs b/musikr/src/main/jni/src/taglib/iostream.rs index 5a256973f..f6c506554 100644 --- a/musikr/src/main/jni/src/taglib/iostream.rs +++ b/musikr/src/main/jni/src/taglib/iostream.rs @@ -54,7 +54,6 @@ impl<'io_stream> DynIOStream<'io_stream> { pub fn write(&mut self, data: &[u8]) { self.0.write_all(data).unwrap(); } - pub fn seek(&mut self, offset: i64, whence: i32) { let pos = match whence { 0 => SeekFrom::Start(offset as u64), diff --git a/musikr/src/main/jni/src/taglib/mp4.rs b/musikr/src/main/jni/src/taglib/mp4.rs index 016f17752..ffae31c13 100644 --- a/musikr/src/main/jni/src/taglib/mp4.rs +++ b/musikr/src/main/jni/src/taglib/mp4.rs @@ -1,5 +1,5 @@ pub use super::bridge::CPPMP4Tag; -use super::bridge::{CPPItemMap, ItemMap_to_entries, CPPItemMapEntry}; +use super::bridge::{CPPItemMap, ItemMap_to_entries, CPPItemMapEntry, CPPMP4Item, MP4ItemType, CPPIntPair}; use super::tk; use super::this::{OwnedThis, RefThis, RefThisMut, ThisMut, This}; use std::collections::HashMap; @@ -30,10 +30,10 @@ impl<'file_ref> ItemMap<'file_ref> { Self { this } } - pub fn to_hashmap(&self) -> HashMap { + pub fn to_hashmap(&self) -> HashMap> { let cxx_vec = ItemMap_to_entries(self.this.pin()); - cxx_vec - .iter() + let vec: Vec<(String, MP4Item<'file_ref>)> = + cxx_vec.iter() .map(|property| { // SAFETY: // - This pin is only used in this unsafe scope. @@ -45,9 +45,158 @@ impl<'file_ref> ItemMap<'file_ref> { let key_ref = property_pin.key(); let key_this = unsafe { RefThis::new(key_ref) }; let key = tk::String::new(key_this).to_string(); - // For now, we're just returning () as a placeholder for MP4::Item - (key, ()) + + let value_ref = property_pin.value(); + let value_this = unsafe { RefThis::new(value_ref) }; + let value = MP4Item::new(value_this); + + (key, value) + }) + .collect(); + + HashMap::from_iter(vec) + } +} + +pub struct MP4Item<'file_ref> { + this: RefThis<'file_ref, CPPMP4Item>, +} + +impl<'file_ref> MP4Item<'file_ref> { + pub fn new(this: RefThis<'file_ref, CPPMP4Item>) -> Self { + Self { this } + } + + pub fn data(&self) -> Option> { + if !self.this.pin().isValid() { + return None; + } + + let item_type = MP4ItemType::from_u32(super::bridge::Item_type(self.this.pin())); + item_type.and_then(|item_type| match item_type { + MP4ItemType::Void => Some(MP4Data::Void), + MP4ItemType::Bool => Some(MP4Data::Bool(self.this.pin().toBool())), + MP4ItemType::Int => Some(MP4Data::Int(self.this.pin().toInt())), + MP4ItemType::IntPair => { + let pair = super::bridge::Item_toIntPair(self.this.pin()); + let pair_this = unsafe { OwnedThis::new(pair) }; + pair_this.map(|this| MP4Data::IntPair(IntPair::new(this))) + }, + MP4ItemType::Byte => Some(MP4Data::Byte(self.this.pin().toByte())), + MP4ItemType::UInt => Some(MP4Data::UInt(self.this.pin().toUInt())), + MP4ItemType::LongLong => Some(MP4Data::LongLong(super::bridge::Item_toLongLong(self.this.pin()))), + MP4ItemType::StringList => { + let string_list = super::bridge::Item_toStringList(self.this.pin()); + let string_list_this = unsafe { OwnedThis::new(string_list) }; + string_list_this.map(|this| MP4Data::StringList(tk::StringList::new(this))) + }, + MP4ItemType::ByteVectorList => { + let byte_vector_list = super::bridge::Item_toByteVectorList(self.this.pin()); + let byte_vector_list_this = unsafe { OwnedThis::new(byte_vector_list) }; + byte_vector_list_this.map(|this| MP4Data::ByteVectorList(tk::ByteVectorList::new(this))) + }, + MP4ItemType::CoverArtList => { + let cover_art_list = super::bridge::Item_toCoverArtList(self.this.pin()); + let cover_art_list_this = unsafe { OwnedThis::new(cover_art_list) }; + cover_art_list_this.map(|this| MP4Data::CoverArtList(CoverArtList::new(this))) + } + }) + } +} + +pub struct CoverArtList<'file_ref> { + this: OwnedThis<'file_ref, super::bridge::CPPCoverArtList>, +} + +impl<'file_ref> CoverArtList<'file_ref> { + pub fn new(this: OwnedThis<'file_ref, super::bridge::CPPCoverArtList>) -> Self { + Self { this } + } + + pub fn to_vec(&self) -> Vec { + let cover_arts = self.this.pin().to_vector(); + cover_arts + .iter() + .map(|ca| { + let ca_pin = unsafe { Pin::new_unchecked(ca) }; + let format = CoverArtFormat::from_u32(ca_pin.format()); + let data = ca_pin.data(); + let data_this = unsafe { RefThis::new(&*data) }; + let data = tk::ByteVector::new(data_this).to_vec(); + CoverArt { format, data } }) .collect() } -} \ No newline at end of file +} + +pub struct IntPair<'file_ref> { + this: OwnedThis<'file_ref, CPPIntPair>, +} + +impl<'file_ref> IntPair<'file_ref> { + pub fn new(this: OwnedThis<'file_ref, CPPIntPair>) -> Self { + Self { this } + } + + pub fn to_tuple(&self) -> Option<(i32, i32)> { + let this = self.this.pin(); + let first = this.first(); + let second = this.second(); + Some((first, second)) + } +} + +pub enum MP4Data<'file_ref> { + Void, + Bool(bool), + Int(i32), + Byte(u8), + UInt(u32), + LongLong(i64), + IntPair(IntPair<'file_ref>), + StringList(tk::OwnedStringList<'file_ref>), + ByteVectorList(tk::OwnedByteVectorList<'file_ref>), + CoverArtList(CoverArtList<'file_ref>), +} + +#[derive(Debug, Clone, PartialEq)] +pub struct CoverArt { + format: CoverArtFormat, + data: Vec, +} + +impl CoverArt { + pub fn new(format: CoverArtFormat, data: Vec) -> Self { + Self { format, data } + } + + pub fn format(&self) -> CoverArtFormat { + self.format + } + + pub fn data(&self) -> &[u8] { + &self.data + } +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum CoverArtFormat { + Unknown, + BMP, + JPEG, + GIF, + PNG, +} + +impl CoverArtFormat { + fn from_u32(value: u32) -> Self { + match value { + 0 => CoverArtFormat::Unknown, + 1 => CoverArtFormat::BMP, + 2 => CoverArtFormat::JPEG, + 3 => CoverArtFormat::GIF, + 4 => CoverArtFormat::PNG, + _ => CoverArtFormat::Unknown, + } + } +} diff --git a/musikr/src/main/jni/src/taglib/tk.rs b/musikr/src/main/jni/src/taglib/tk.rs index 829751381..727afbbb0 100644 --- a/musikr/src/main/jni/src/taglib/tk.rs +++ b/musikr/src/main/jni/src/taglib/tk.rs @@ -1,4 +1,4 @@ -use super::bridge::{self, CPPByteVector, CPPString, CPPStringList}; +use super::bridge::{self, CPPByteVector, CPPByteVectorList, CPPString, CPPStringList}; use super::this::{RefThis, RefThisMut, This, OwnedThis}; use cxx::{memory::UniquePtrTarget, UniquePtr}; use std::marker::PhantomData; @@ -94,3 +94,27 @@ impl<'file_ref, T: This<'file_ref, CPPByteVector>> ByteVector<'file_ref, T> { pub type OwnedByteVector<'file_ref> = ByteVector<'file_ref, OwnedThis<'file_ref, CPPByteVector>>; pub type RefByteVector<'file_ref> = ByteVector<'file_ref, RefThis<'file_ref, CPPByteVector>>; pub type RefByteVectorMut<'file_ref> = ByteVector<'file_ref, RefThisMut<'file_ref, CPPByteVector>>; + +pub struct ByteVectorList<'file_ref, T: This<'file_ref, CPPByteVectorList>> { + _data: PhantomData<&'file_ref CPPByteVectorList>, + this: T, +} + +impl<'file_ref, T: This<'file_ref, CPPByteVectorList>> ByteVectorList<'file_ref, T> { + pub(super) fn new(this: T) -> Self { + Self { _data: PhantomData, this } + } + + pub fn to_vec(&self) -> Vec> { + let cxx_values = bridge::ByteVectorList_to_vector(self.this.pin()); + cxx_values + .iter() + .map(|value| ByteVector::new(unsafe { RefThis::new(value) }).to_vec()) + .collect() + } +} + +pub type OwnedByteVectorList<'file_ref> = ByteVectorList<'file_ref, OwnedThis<'file_ref, CPPByteVectorList>>; +pub type RefByteVectorList<'file_ref> = ByteVectorList<'file_ref, RefThis<'file_ref, CPPByteVectorList>>; +pub type RefByteVectorListMut<'file_ref> = ByteVectorList<'file_ref, RefThisMut<'file_ref, CPPByteVectorList>>; +