diff --git a/musikr/src/main/jni/shim/picture_shim.cpp b/musikr/src/main/jni/shim/picture_shim.cpp new file mode 100644 index 000000000..781877935 --- /dev/null +++ b/musikr/src/main/jni/shim/picture_shim.cpp @@ -0,0 +1,15 @@ +#include "picture_shim.hpp" + +namespace taglib_shim { + std::unique_ptr Picture_mimeType(const TagLib::FLAC::Picture& picture) { + return std::make_unique(picture.mimeType()); + } + + std::unique_ptr Picture_description(const TagLib::FLAC::Picture& picture) { + return std::make_unique(picture.description()); + } + + std::unique_ptr Picture_data(const TagLib::FLAC::Picture& picture) { + return std::make_unique(picture.data()); + } +} \ No newline at end of file diff --git a/musikr/src/main/jni/shim/picture_shim.hpp b/musikr/src/main/jni/shim/picture_shim.hpp new file mode 100644 index 000000000..72a5c85bf --- /dev/null +++ b/musikr/src/main/jni/shim/picture_shim.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "taglib/flacpicture.h" +#include "taglib/tstring.h" +#include "taglib/tbytevector.h" +#include + +namespace taglib_shim { + std::unique_ptr Picture_mimeType(const TagLib::FLAC::Picture& picture); + std::unique_ptr Picture_description(const TagLib::FLAC::Picture& picture); + std::unique_ptr Picture_data(const TagLib::FLAC::Picture& picture); +} \ 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 3f6bf9fd7..b07992c7f 100644 --- a/musikr/src/main/jni/shim/tk_shim.cpp +++ b/musikr/src/main/jni/shim/tk_shim.cpp @@ -33,4 +33,41 @@ namespace taglib_shim return result; } + std::unique_ptr> FLACFile_pictureList_to_vector(TagLib::FLAC::File &file) + { + std::unique_ptr> result = std::make_unique>(); + const auto pictures = file.pictureList(); + for (const auto &picture : pictures) + { + result->push_back(PictureRef(picture)); + } + return result; + } + + std::unique_ptr> XiphComment_pictureList_to_vector(TagLib::Ogg::XiphComment &comment) + { + std::unique_ptr> result = std::make_unique>(); + const auto pictures = comment.pictureList(); + for (const auto &picture : pictures) + { + result->push_back(PictureRef(picture)); + } + return result; + } + + rust::String String_to_string(const TagLib::String &str) + { + return rust::String(str.to8Bit()); + } + + std::unique_ptr> ByteVector_to_bytes(const TagLib::ByteVector &data) + { + auto result = std::make_unique>(); + result->reserve(data.size()); + for (size_t i = 0; i < data.size(); i++) + { + result->push_back(static_cast(data[i])); + } + return result; + } } diff --git a/musikr/src/main/jni/shim/tk_shim.hpp b/musikr/src/main/jni/shim/tk_shim.hpp index e79786998..7b10351b7 100644 --- a/musikr/src/main/jni/shim/tk_shim.hpp +++ b/musikr/src/main/jni/shim/tk_shim.hpp @@ -4,8 +4,14 @@ #include "taglib/xiphcomment.h" #include "taglib/tstring.h" #include "taglib/tstringlist.h" +#include "taglib/flacpicture.h" +#include "taglib/flacfile.h" +#include "taglib/tbytevector.h" #include #include +#include +#include +#include "rust/cxx.h" namespace taglib_shim { @@ -21,6 +27,17 @@ namespace taglib_shim TagLib::StringList value_; }; + struct PictureRef { + PictureRef(const TagLib::FLAC::Picture* picture) : picture_(picture) {} + const TagLib::FLAC::Picture* get() const { return picture_; } + private: + const TagLib::FLAC::Picture* picture_; + }; + std::unique_ptr> SimplePropertyMap_to_vector(const TagLib::SimplePropertyMap &map); std::unique_ptr> StringList_to_vector(const TagLib::StringList &list); + std::unique_ptr> FLACFile_pictureList_to_vector(TagLib::FLAC::File &file); + std::unique_ptr> XiphComment_pictureList_to_vector(TagLib::Ogg::XiphComment &comment); + rust::String String_to_string(const TagLib::String &str); + std::unique_ptr> ByteVector_to_bytes(const TagLib::ByteVector &data); } \ 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 ee191f993..400b2bd1b 100644 --- a/musikr/src/main/jni/src/taglib/bridge.rs +++ b/musikr/src/main/jni/src/taglib/bridge.rs @@ -25,9 +25,12 @@ mod bridge_impl { include!("taglib/vorbisfile.h"); include!("taglib/xiphcomment.h"); include!("taglib/tiostream.h"); + include!("taglib/flacpicture.h"); + include!("taglib/tbytevector.h"); include!("shim/iostream_shim.hpp"); include!("shim/file_shim.hpp"); include!("shim/tk_shim.hpp"); + include!("shim/picture_shim.hpp"); #[namespace = "TagLib"] #[cxx_name = "IOStream"] @@ -64,6 +67,28 @@ mod bridge_impl { #[cxx_name = "channels"] fn channels(self: Pin<&CppAudioProperties>) -> i32; + #[namespace = "TagLib::FLAC"] + #[cxx_name = "Picture"] + type CPPFLACPicture; + #[namespace = "taglib_shim"] + fn Picture_mimeType(picture: &CPPFLACPicture) -> UniquePtr; + #[namespace = "taglib_shim"] + fn Picture_description(picture: &CPPFLACPicture) -> UniquePtr; + #[cxx_name = "width"] + fn width(self: Pin<&CPPFLACPicture>) -> i32; + #[cxx_name = "height"] + fn height(self: Pin<&CPPFLACPicture>) -> i32; + #[cxx_name = "colorDepth"] + fn colorDepth(self: Pin<&CPPFLACPicture>) -> i32; + #[cxx_name = "numColors"] + fn numColors(self: Pin<&CPPFLACPicture>) -> i32; + #[namespace = "taglib_shim"] + fn Picture_data(picture: &CPPFLACPicture) -> UniquePtr; + + #[namespace = "TagLib"] + #[cxx_name = "ByteVector"] + type CPPByteVector; + #[namespace = "TagLib::Ogg"] #[cxx_name = "XiphComment"] type CPPXiphComment; @@ -148,6 +173,20 @@ mod bridge_impl { type CPPStringList; #[namespace = "taglib_shim"] fn StringList_to_vector(string_list: Pin<&CPPStringList>) -> UniquePtr>; + + #[namespace = "taglib_shim"] + type PictureRef; + fn get(self: &PictureRef) -> *const CPPFLACPicture; + + #[namespace = "taglib_shim"] + fn FLACFile_pictureList_to_vector(file: Pin<&mut CPPFLACFile>) -> UniquePtr>; + #[namespace = "taglib_shim"] + fn XiphComment_pictureList_to_vector(comment: Pin<&mut CPPXiphComment>) -> UniquePtr>; + + #[namespace = "taglib_shim"] + fn String_to_string(str: &CPPString) -> String; + #[namespace = "taglib_shim"] + fn ByteVector_to_bytes(data: &CPPByteVector) -> UniquePtr>; } } diff --git a/musikr/src/main/jni/src/taglib/flac.rs b/musikr/src/main/jni/src/taglib/flac.rs index 1fd99b009..0759159b6 100644 --- a/musikr/src/main/jni/src/taglib/flac.rs +++ b/musikr/src/main/jni/src/taglib/flac.rs @@ -1,5 +1,7 @@ pub use super::bridge::CPPFLACFile; +pub use super::bridge::CPPFLACPicture; pub use super::xiph::XiphComment; +use super::bridge::{FLACFile_pictureList_to_vector, String_to_string, ByteVector_to_bytes, Picture_mimeType, Picture_description, Picture_data}; use std::pin::Pin; pub struct FLACFile<'a> { @@ -25,9 +27,63 @@ impl<'a> FLACFile<'a> { let tag_ref = unsafe { // SAFETY: This pointer is a valid type, and can only used and accessed // via this function and thus cannot be mutated, satisfying the aliasing rules. - tag.as_ref() + tag.as_mut() }; let tag_pin = tag_ref.map(|tag| unsafe { Pin::new_unchecked(tag) }); tag_pin.map(|tag| XiphComment::new(tag)) } -} \ No newline at end of file + + pub fn picture_list(&mut self) -> Vec> { + let pictures = FLACFile_pictureList_to_vector(self.this.as_mut()); + let mut result = Vec::new(); + for picture_ref in pictures.iter() { + let picture_ptr = picture_ref.get(); + let picture_ref = unsafe { + // SAFETY: This pointer is a valid type, and can only used and accessed + // via this function and thus cannot be mutated, satisfying the aliasing rules. + picture_ptr.as_ref().unwrap() + }; + let picture_pin = unsafe { Pin::new_unchecked(picture_ref) }; + result.push(Picture::new(picture_pin)); + } + result + } +} + +pub struct Picture<'a> { + this: Pin<&'a CPPFLACPicture> +} + +impl<'a> Picture<'a> { + pub(super) fn new(this: Pin<&'a CPPFLACPicture>) -> Self { + Self { this } + } + + pub fn mime_type(&self) -> String { + String_to_string(Picture_mimeType(self.this.get_ref()).as_ref().unwrap()) + } + + pub fn description(&self) -> String { + String_to_string(Picture_description(self.this.get_ref()).as_ref().unwrap()) + } + + pub fn width(&self) -> i32 { + self.this.width() + } + + pub fn height(&self) -> i32 { + self.this.height() + } + + pub fn color_depth(&self) -> i32 { + self.this.colorDepth() + } + + pub fn num_colors(&self) -> i32 { + self.this.numColors() + } + + pub fn data(&self) -> Vec { + ByteVector_to_bytes(Picture_data(self.this.get_ref()).as_ref().unwrap()).iter().map(|b| *b).collect() + } +} diff --git a/musikr/src/main/jni/src/taglib/ogg.rs b/musikr/src/main/jni/src/taglib/ogg.rs index 580fb7e6b..d9ea32958 100644 --- a/musikr/src/main/jni/src/taglib/ogg.rs +++ b/musikr/src/main/jni/src/taglib/ogg.rs @@ -24,7 +24,7 @@ impl<'a> VorbisFile<'a> { let tag_ref = unsafe { // SAFETY: This pointer is a valid type, and can only used and accessed // via this function and thus cannot be mutated, satisfying the aliasing rules. - tag.as_ref() + tag.as_mut() }; let tag_pin = tag_ref.map(|tag| unsafe { Pin::new_unchecked(tag) }); tag_pin.map(|tag| XiphComment::new(tag)) @@ -53,7 +53,7 @@ impl <'a> OpusFile<'a> { let tag_ref = unsafe { // SAFETY: This pointer is a valid type, and can only used and accessed // via this function and thus cannot be mutated, satisfying the aliasing rules. - tag.as_ref() + tag.as_mut() }; let tag_pin = tag_ref.map(|tag| unsafe { Pin::new_unchecked(tag) }); tag_pin.map(|tag| XiphComment::new(tag)) diff --git a/musikr/src/main/jni/src/taglib/xiph.rs b/musikr/src/main/jni/src/taglib/xiph.rs index 592b4983f..2f23e3788 100644 --- a/musikr/src/main/jni/src/taglib/xiph.rs +++ b/musikr/src/main/jni/src/taglib/xiph.rs @@ -1,19 +1,37 @@ pub use super::bridge::CPPXiphComment; +pub use super::flac::Picture; +use super::bridge::XiphComment_pictureList_to_vector; use super::tk::SimplePropertyMap; use std::pin::Pin; pub struct XiphComment<'a> { - this: Pin<&'a CPPXiphComment> + this: Pin<&'a mut CPPXiphComment> } impl<'a> XiphComment<'a> { - pub(super) fn new(this: Pin<&'a CPPXiphComment>) -> Self { + pub(super) fn new(this: Pin<&'a mut CPPXiphComment>) -> Self { Self { this } } - pub fn field_list_map(&self) -> SimplePropertyMap<'a> { - let map = self.this.fieldListMap(); + pub fn field_list_map(&'a self) -> SimplePropertyMap<'a> { + let map = self.this.as_ref().fieldListMap(); let map_pin = unsafe { Pin::new_unchecked(map) }; SimplePropertyMap::new(map_pin) } + + pub fn picture_list(&mut self) -> Vec> { + let pictures = XiphComment_pictureList_to_vector(self.this.as_mut()); + let mut result = Vec::new(); + for picture_ref in pictures.iter() { + let picture_ptr = picture_ref.get(); + let picture_ref = unsafe { + // SAFETY: This pointer is a valid type, and can only used and accessed + // via this function and thus cannot be mutated, satisfying the aliasing rules. + picture_ptr.as_ref().unwrap() + }; + let picture_pin = unsafe { Pin::new_unchecked(picture_ref) }; + result.push(Picture::new(picture_pin)); + } + result + } }