musikr: implement main flow

This commit is contained in:
Alexander Capehart 2025-02-17 21:09:43 -07:00
parent de9a60d182
commit 8415db30ff
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
19 changed files with 294 additions and 174 deletions

View file

@ -1,10 +1,12 @@
use jni::{objects::{JByteArray, JClass, JMap, JObject, JString, JValueGen}, sys::jlong, JNIEnv}; use jni::{
use std::rc::Rc; objects::{JObject, JValueGen},
use std::cell::RefCell; sys::jlong,
JNIEnv,
use crate::taglib::{
id3v1, id3v2, xiph, mp4, tk, audioproperties,
}; };
use std::cell::RefCell;
use std::rc::Rc;
use crate::taglib::{audioproperties, id3v1, id3v2, mp4, xiph};
use crate::tagmap::JTagMap; use crate::tagmap::JTagMap;
@ -56,7 +58,8 @@ impl<'local, 'file_ref> JMetadataBuilder<'local, 'file_ref> {
for mut frame in frames.to_vec() { for mut frame in frames.to_vec() {
if let Some(text_frame) = frame.as_text_identification() { if let Some(text_frame) = frame.as_text_identification() {
if let Some(field_list) = text_frame.field_list() { if let Some(field_list) = text_frame.field_list() {
let values: Vec<String> = field_list.to_vec() let values: Vec<String> = field_list
.to_vec()
.into_iter() .into_iter()
.map(|s| s.to_string()) .map(|s| s.to_string())
.collect(); .collect();
@ -110,7 +113,10 @@ impl<'local, 'file_ref> JMetadataBuilder<'local, 'file_ref> {
let covers = cover_list.to_vec(); let covers = cover_list.to_vec();
// Prefer PNG/JPEG covers // Prefer PNG/JPEG covers
let preferred_cover = covers.iter().find(|c| { let preferred_cover = covers.iter().find(|c| {
matches!(c.format(), mp4::CoverArtFormat::PNG | mp4::CoverArtFormat::JPEG) matches!(
c.format(),
mp4::CoverArtFormat::PNG | mp4::CoverArtFormat::JPEG
)
}); });
if let Some(cover) = preferred_cover { if let Some(cover) = preferred_cover {
@ -125,7 +131,8 @@ impl<'local, 'file_ref> JMetadataBuilder<'local, 'file_ref> {
if let Some(data) = item.data() { if let Some(data) = item.data() {
match data { match data {
mp4::MP4Data::StringList(list) => { mp4::MP4Data::StringList(list) => {
let values: Vec<String> = list.to_vec().into_iter().map(|s| s.to_string()).collect(); let values: Vec<String> =
list.to_vec().into_iter().map(|s| s.to_string()).collect();
if key.starts_with("----") { if key.starts_with("----") {
if let Some(split_idx) = key.find(':') { if let Some(split_idx) = key.find(':') {
let (atom_name, atom_desc) = key.split_at(split_idx); let (atom_name, atom_desc) = key.split_at(split_idx);
@ -158,12 +165,18 @@ impl<'local, 'file_ref> JMetadataBuilder<'local, 'file_ref> {
pub fn build(&self) -> JObject { pub fn build(&self) -> JObject {
// Create Properties object // Create Properties object
let properties_class = self.env.borrow_mut().find_class("org/oxycblt/musikr/metadata/Properties").unwrap(); let properties_class = self
.env
.borrow_mut()
.find_class("org/oxycblt/musikr/metadata/Properties")
.unwrap();
let properties = if let Some(props) = &self.properties { let properties = if let Some(props) = &self.properties {
let mime_type = self.mime_type.as_deref().unwrap_or("").to_string(); let mime_type = self.mime_type.as_deref().unwrap_or("").to_string();
let j_mime_type = self.env.borrow().new_string(mime_type).unwrap(); let j_mime_type = self.env.borrow().new_string(mime_type).unwrap();
self.env.borrow_mut().new_object( self.env
.borrow_mut()
.new_object(
properties_class, properties_class,
"(Ljava/lang/String;JII)V", "(Ljava/lang/String;JII)V",
&[ &[
@ -172,27 +185,47 @@ impl<'local, 'file_ref> JMetadataBuilder<'local, 'file_ref> {
(props.bitrate() as i32).into(), (props.bitrate() as i32).into(),
(props.sample_rate() as i32).into(), (props.sample_rate() as i32).into(),
], ],
).unwrap() )
.unwrap()
} else { } else {
let empty_mime = self.env.borrow().new_string("").unwrap(); let empty_mime = self.env.borrow().new_string("").unwrap();
self.env.borrow_mut().new_object( self.env
.borrow_mut()
.new_object(
properties_class, properties_class,
"(Ljava/lang/String;JII)V", "(Ljava/lang/String;JII)V",
&[JValueGen::from(&empty_mime), 0i64.into(), 0i32.into(), 0i32.into()], &[
).unwrap() JValueGen::from(&empty_mime),
0i64.into(),
0i32.into(),
0i32.into(),
],
)
.unwrap()
}; };
// Create cover byte array if present // Create cover byte array if present
let cover_array = if let Some(cover_data) = &self.cover { let cover_array = if let Some(cover_data) = &self.cover {
let array = self.env.borrow().new_byte_array(cover_data.len() as i32).unwrap(); let array = self
self.env.borrow().set_byte_array_region(&array, 0, bytemuck::cast_slice(cover_data)).unwrap(); .env
.borrow()
.new_byte_array(cover_data.len() as i32)
.unwrap();
self.env
.borrow()
.set_byte_array_region(&array, 0, bytemuck::cast_slice(cover_data))
.unwrap();
array.into() array.into()
} else { } else {
JObject::null() JObject::null()
}; };
// Create Metadata object // Create Metadata object
let metadata_class = self.env.borrow_mut().find_class("org/oxycblt/musikr/metadata/Metadata").unwrap(); let metadata_class = self
.env
.borrow_mut()
.find_class("org/oxycblt/musikr/metadata/Metadata")
.unwrap();
self.env.borrow_mut().new_object( self.env.borrow_mut().new_object(
metadata_class, metadata_class,
"(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;[BLorg/oxycblt/musikr/metadata/Properties;)V", "(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;[BLorg/oxycblt/musikr/metadata/Properties;)V",

View file

@ -1,7 +1,7 @@
use crate::taglib::iostream::IOStream; use crate::taglib::iostream::IOStream;
use crate::SharedEnv; use crate::SharedEnv;
use jni::objects::{JObject, JValue}; use jni::objects::{JObject, JValue};
use std::io::{Read, Seek, SeekFrom, Write}; use std::io::SeekFrom;
pub struct JInputStream<'local> { pub struct JInputStream<'local> {
env: SharedEnv<'local>, env: SharedEnv<'local>,

View file

@ -1,36 +1,79 @@
use jni::objects::{JClass, JObject}; use jni::objects::{JClass, JObject};
use jni::sys::jstring; use jni::sys::jobject;
use jni::JNIEnv; use jni::JNIEnv;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
mod jbuilder;
mod jstream; mod jstream;
mod taglib; mod taglib;
mod tagmap; mod tagmap;
mod jbuilder;
use jbuilder::JMetadataBuilder;
use jstream::JInputStream; use jstream::JInputStream;
use taglib::file_ref::FileRef; use taglib::file_ref::FileRef;
use jbuilder::JMetadataBuilder;
type SharedEnv<'local> = Rc<RefCell<JNIEnv<'local>>>; type SharedEnv<'local> = Rc<RefCell<JNIEnv<'local>>>;
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_oxycblt_musikr_metadata_MetadataJNI_openFile<'local>( pub extern "C" fn Java_org_oxycblt_musikr_metadata_MetadataJNI_openFile<'local>(
mut env: JNIEnv<'local>, env: JNIEnv<'local>,
_class: JClass<'local>, _class: JClass<'local>,
input: JObject<'local>, input: JObject<'local>,
) -> jstring { ) -> jobject {
// Create JInputStream from the Java input stream // Create JInputStream from the Java input stream
let shared_env = Rc::new(RefCell::new(env)); let shared_env = Rc::new(RefCell::new(env));
let mut stream = JInputStream::new(shared_env.clone(), input); let stream = JInputStream::new(shared_env.clone(), input);
let file_ref = FileRef::new(stream); let file_ref = FileRef::new(stream);
let file = file_ref.file();
let mut jbuilder = JMetadataBuilder::new(shared_env.clone());
match file {
Some(mut file) => {
if let Some(properties) = file.audio_properties() {
jbuilder.set_properties(properties);
}
if let Some(vorbis) = file.as_vorbis() {
jbuilder.set_mime_type("audio/ogg");
if let Some(tag) = vorbis.xiph_comments() {
jbuilder.set_xiph(&tag);
}
}
if let Some(opus) = file.as_opus() {
jbuilder.set_mime_type("audio/opus");
if let Some(tag) = opus.xiph_comments() {
jbuilder.set_xiph(&tag);
}
}
if let Some(mut flac) = file.as_flac() {
jbuilder.set_mime_type("audio/flac");
if let Some(tag) = flac.xiph_comments() {
jbuilder.set_xiph(&tag);
}
}
if let Some(mut mpeg) = file.as_mpeg() {
jbuilder.set_mime_type("audio/mpeg");
if let Some(tag) = mpeg.id3v1_tag() {
jbuilder.set_id3v1(&tag);
}
if let Some(tag) = mpeg.id3v2_tag() {
jbuilder.set_id3v2(&tag);
}
}
if let Some(mp4) = file.as_mp4() {
jbuilder.set_mime_type("audio/mp4");
if let Some(tag) = mp4.tag() {
jbuilder.set_mp4(&tag);
}
}
if let Some(mut wav) = file.as_wav() {
jbuilder.set_mime_type("audio/wav");
if let Some(tag) = wav.id3v2_tag() {
jbuilder.set_id3v2(&tag);
}
}
}
None => {}
}
jbuilder.build().into_raw()
// Return the title
let output = shared_env
.borrow_mut()
.new_string("title")
.expect("Couldn't create string!");
output.into_raw()
} }

View file

@ -1,6 +1,5 @@
use super::bridge::CppAudioProperties; use super::bridge::CppAudioProperties;
use super::this::{RefThis, This}; use super::this::RefThis;
use std::pin::Pin;
pub struct AudioProperties<'file_ref> { pub struct AudioProperties<'file_ref> {
this: RefThis<'file_ref, CppAudioProperties>, this: RefThis<'file_ref, CppAudioProperties>,

View file

@ -51,7 +51,9 @@ mod bridge_impl {
#[namespace = "TagLib"] #[namespace = "TagLib"]
#[cxx_name = "IOStream"] #[cxx_name = "IOStream"]
type CPPIOStream<'io_stream>; type CPPIOStream<'io_stream>;
fn wrap_RsIOStream<'io_stream>(stream: Box<DynIOStream<'io_stream>>) -> UniquePtr<CPPIOStream<'io_stream>>; fn wrap_RsIOStream<'io_stream>(
stream: Box<DynIOStream<'io_stream>>,
) -> UniquePtr<CPPIOStream<'io_stream>>;
#[namespace = "TagLib"] #[namespace = "TagLib"]
#[cxx_name = "FileRef"] #[cxx_name = "FileRef"]
@ -258,9 +260,7 @@ mod bridge_impl {
#[cxx_name = "FrameList"] #[cxx_name = "FrameList"]
type CPPID3v2FrameList; type CPPID3v2FrameList;
#[namespace = "taglib_shim"] #[namespace = "taglib_shim"]
fn FrameList_to_vector( fn FrameList_to_vector(list: &CPPID3v2FrameList) -> UniquePtr<CxxVector<CPPFramePointer>>;
list: &CPPID3v2FrameList,
) -> UniquePtr<CxxVector<CPPFramePointer>>;
#[namespace = "taglib_shim"] #[namespace = "taglib_shim"]
#[cxx_name = "FramePointer"] #[cxx_name = "FramePointer"]
@ -318,9 +318,7 @@ mod bridge_impl {
#[cxx_name = "StringList"] #[cxx_name = "StringList"]
type CPPStringList; type CPPStringList;
#[namespace = "taglib_shim"] #[namespace = "taglib_shim"]
fn StringList_to_vector( fn StringList_to_vector(string_list: &CPPStringList) -> UniquePtr<CxxVector<CPPString>>;
string_list: &CPPStringList,
) -> UniquePtr<CxxVector<CPPString>>;
#[namespace = "TagLib"] #[namespace = "TagLib"]
#[cxx_name = "ByteVector"] #[cxx_name = "ByteVector"]
@ -332,7 +330,9 @@ mod bridge_impl {
#[cxx_name = "ByteVectorList"] #[cxx_name = "ByteVectorList"]
type CPPByteVectorList; type CPPByteVectorList;
#[namespace = "taglib_shim"] #[namespace = "taglib_shim"]
fn ByteVectorList_to_vector(list: &CPPByteVectorList) -> UniquePtr<CxxVector<CPPByteVector>>; fn ByteVectorList_to_vector(
list: &CPPByteVectorList,
) -> UniquePtr<CxxVector<CPPByteVector>>;
} }
} }

View file

@ -1,16 +1,15 @@
use super::audioproperties::AudioProperties; use super::audioproperties::AudioProperties;
use super::bridge::{self, CPPFile, CPPMPEGFile}; use super::bridge::{self, CPPFile};
use super::flac::FLACFile; use super::flac::FLACFile;
use super::id3v2::ID3v2Tag;
use super::mp4::MP4File; use super::mp4::MP4File;
use super::mpeg::MPEGFile; use super::mpeg::MPEGFile;
use super::ogg::OpusFile; use super::ogg::OpusFile;
use super::ogg::VorbisFile; use super::ogg::VorbisFile;
use super::this::{RefThisMut, RefThis, This, ThisMut}; use super::riff::WAVFile;
use std::pin::Pin; use super::this::{RefThis, RefThisMut};
pub struct File<'file_ref> { pub struct File<'file_ref> {
this: RefThisMut<'file_ref, CPPFile> this: RefThisMut<'file_ref, CPPFile>,
} }
impl<'file_ref> File<'file_ref> { impl<'file_ref> File<'file_ref> {
@ -118,12 +117,16 @@ impl<'file_ref> File<'file_ref> {
} }
pub fn as_mp4(&mut self) -> Option<MP4File<'file_ref>> { pub fn as_mp4(&mut self) -> Option<MP4File<'file_ref>> {
let mp4_file = unsafe { let mp4_file = unsafe { bridge::File_asMP4(self.this.ptr_mut()) };
bridge::File_asMP4(self.this.ptr_mut())
};
let mp4_ref = unsafe { mp4_file.as_mut() }; let mp4_ref = unsafe { mp4_file.as_mut() };
let mp4_this = mp4_ref.map(|mp4| RefThisMut::new(mp4)); let mp4_this = mp4_ref.map(|mp4| RefThisMut::new(mp4));
mp4_this.map(|this| MP4File::new(this)) mp4_this.map(|this| MP4File::new(this))
} }
pub fn as_wav(&mut self) -> Option<WAVFile<'file_ref>> {
let wav_file = unsafe { bridge::File_asWAV(self.this.ptr_mut()) };
let wav_ref = unsafe { wav_file.as_mut() };
let wav_this = wav_ref.map(|wav| RefThisMut::new(wav));
wav_this.map(|this| WAVFile::new(this))
}
} }

View file

@ -1,17 +1,16 @@
pub use super::bridge::CPPFLACFile; pub use super::bridge::CPPFLACFile;
pub use super::bridge::CPPFLACPicture; pub use super::bridge::CPPFLACPicture;
use super::bridge::{CPPPictureList, FLACFile_pictureList, PictureList_to_vector, Picture_data, CPPByteVector}; use super::bridge::{
CPPPictureList, FLACFile_pictureList, PictureList_to_vector, Picture_data,
};
use super::id3v1::ID3v1Tag; use super::id3v1::ID3v1Tag;
use super::id3v2::ID3v2Tag; use super::id3v2::ID3v2Tag;
use super::this::{OwnedThis, RefThis, RefThisMut, ThisMut};
use super::tk::{ByteVector, OwnedByteVector}; use super::tk::{ByteVector, OwnedByteVector};
pub use super::xiph::XiphComment; pub use super::xiph::XiphComment;
use super::this::{OwnedThis, RefThisMut, RefThis, This, ThisMut};
use cxx::UniquePtr;
use std::marker::PhantomData;
use std::pin::Pin;
pub struct FLACFile<'file_ref> { pub struct FLACFile<'file_ref> {
this: RefThisMut<'file_ref, CPPFLACFile> this: RefThisMut<'file_ref, CPPFLACFile>,
} }
impl<'file_ref> FLACFile<'file_ref> { impl<'file_ref> FLACFile<'file_ref> {
@ -19,7 +18,6 @@ impl<'file_ref> FLACFile<'file_ref> {
Self { this } Self { this }
} }
pub fn xiph_comments(&mut self) -> Option<XiphComment<'file_ref>> { pub fn xiph_comments(&mut self) -> Option<XiphComment<'file_ref>> {
let tag = self.this.pin_mut().xiphComment(false); let tag = self.this.pin_mut().xiphComment(false);
let tag_ref = unsafe { let tag_ref = unsafe {

View file

@ -1,6 +1,6 @@
use super::bridge::{self, CPPID3v1Tag}; use super::bridge::{self, CPPID3v1Tag};
use super::this::{RefThisMut, RefThis, This, OwnedThis}; use super::this::{OwnedThis, RefThisMut};
use super::tk::{String, OwnedString}; use super::tk::{OwnedString, String};
pub struct ID3v1Tag<'file_ref> { pub struct ID3v1Tag<'file_ref> {
this: RefThisMut<'file_ref, CPPID3v1Tag>, this: RefThisMut<'file_ref, CPPID3v1Tag>,

View file

@ -1,9 +1,9 @@
use super::bridge::{ use super::bridge::{
self, CPPID3v2AttachedPictureFrame, CPPID3v2Frame, CPPID3v2FrameList, CPPID3v2Tag, self, CPPID3v2AttachedPictureFrame, CPPID3v2Frame, CPPID3v2FrameList,
CPPID3v2TextIdentificationFrame, CPPID3v2UserTextIdentificationFrame, CPPStringList, CPPByteVector, CPPID3v2Tag, CPPID3v2TextIdentificationFrame, CPPID3v2UserTextIdentificationFrame,
}; };
use super::tk::{self, ByteVector, StringList, OwnedByteVector, OwnedStringList}; use super::this::{OwnedThis, RefThis, RefThisMut};
use super::this::{OwnedThis, RefThisMut, RefThis, This}; use super::tk::{self, ByteVector, OwnedByteVector, OwnedStringList, StringList};
pub struct ID3v2Tag<'file_ref> { pub struct ID3v2Tag<'file_ref> {
this: RefThisMut<'file_ref, CPPID3v2Tag>, this: RefThisMut<'file_ref, CPPID3v2Tag>,

View file

@ -1,7 +1,6 @@
use super::bridge::{self, CPPIOStream}; use super::bridge::{self, CPPIOStream};
use cxx::UniquePtr; use cxx::UniquePtr;
use std::io::{Read, Seek, SeekFrom, Write}; use std::io::{Seek, SeekFrom};
use std::pin::Pin;
pub trait IOStream { pub trait IOStream {
fn read_block(&mut self, buffer: &mut [u8]) -> usize; fn read_block(&mut self, buffer: &mut [u8]) -> usize;
@ -22,9 +21,7 @@ impl<'io_stream> BridgedIOStream<'io_stream> {
pub fn new<T: IOStream + 'io_stream>(stream: T) -> Self { pub fn new<T: IOStream + 'io_stream>(stream: T) -> Self {
let rs_stream: Box<DynIOStream<'io_stream>> = Box::new(DynIOStream(Box::new(stream))); let rs_stream: Box<DynIOStream<'io_stream>> = Box::new(DynIOStream(Box::new(stream)));
let cpp_stream: UniquePtr<CPPIOStream<'io_stream>> = bridge::wrap_RsIOStream(rs_stream); let cpp_stream: UniquePtr<CPPIOStream<'io_stream>> = bridge::wrap_RsIOStream(rs_stream);
BridgedIOStream { BridgedIOStream { cpp_stream }
cpp_stream,
}
} }
pub fn cpp_stream(&self) -> &UniquePtr<CPPIOStream> { pub fn cpp_stream(&self) -> &UniquePtr<CPPIOStream> {

View file

@ -1,15 +1,15 @@
mod bridge;
mod this;
pub mod iostream;
pub mod file_ref;
pub mod file;
pub mod audioproperties; pub mod audioproperties;
pub mod ogg; mod bridge;
pub mod mpeg; pub mod file;
pub mod file_ref;
pub mod flac; pub mod flac;
pub mod xiph;
pub mod tk;
pub mod id3v2;
pub mod id3v1; pub mod id3v1;
pub mod id3v2;
pub mod iostream;
pub mod mp4; pub mod mp4;
pub mod mpeg;
pub mod ogg;
pub mod riff; pub mod riff;
mod this;
pub mod tk;
pub mod xiph;

View file

@ -1,9 +1,11 @@
pub use super::bridge::CPPMP4Tag; pub use super::bridge::CPPMP4Tag;
use super::bridge::{CPPFile, CPPIntPair, CPPItemMap, CPPItemMapEntry, CPPMP4File, CPPMP4Item, ItemMap_to_entries, MP4ItemType}; use super::bridge::{
CPPIntPair, CPPItemMap, CPPMP4File, CPPMP4Item, ItemMap_to_entries,
MP4ItemType,
};
use super::this::{OwnedThis, RefThis, RefThisMut};
use super::tk; use super::tk;
use super::this::{OwnedThis, RefThis, RefThisMut, ThisMut, This};
use std::collections::HashMap; use std::collections::HashMap;
use std::pin::Pin;
pub struct MP4File<'file_ref> { pub struct MP4File<'file_ref> {
this: RefThisMut<'file_ref, CPPMP4File>, this: RefThisMut<'file_ref, CPPMP4File>,
@ -53,8 +55,8 @@ impl<'file_ref> ItemMap<'file_ref> {
pub fn to_hashmap(&self) -> HashMap<String, MP4Item<'file_ref>> { pub fn to_hashmap(&self) -> HashMap<String, MP4Item<'file_ref>> {
let cxx_vec = ItemMap_to_entries(self.this.as_ref()); let cxx_vec = ItemMap_to_entries(self.this.as_ref());
let vec: Vec<(String, MP4Item<'file_ref>)> = let vec: Vec<(String, MP4Item<'file_ref>)> = cxx_vec
cxx_vec.iter() .iter()
.map(|property| { .map(|property| {
// SAFETY: // SAFETY:
// - This pin is only used in this unsafe scope. // - This pin is only used in this unsafe scope.
@ -101,24 +103,30 @@ impl<'file_ref> MP4Item<'file_ref> {
let pair = super::bridge::Item_toIntPair(self.this.as_ref()); let pair = super::bridge::Item_toIntPair(self.this.as_ref());
let pair_this = OwnedThis::new(pair).unwrap(); let pair_this = OwnedThis::new(pair).unwrap();
Some(MP4Data::IntPair(IntPair::new(pair_this))) Some(MP4Data::IntPair(IntPair::new(pair_this)))
}, }
MP4ItemType::Byte => Some(MP4Data::Byte(self.this.as_ref().toByte())), MP4ItemType::Byte => Some(MP4Data::Byte(self.this.as_ref().toByte())),
MP4ItemType::UInt => Some(MP4Data::UInt(self.this.as_ref().toUInt())), MP4ItemType::UInt => Some(MP4Data::UInt(self.this.as_ref().toUInt())),
MP4ItemType::LongLong => Some(MP4Data::LongLong(super::bridge::Item_toLongLong(self.this.as_ref()))), MP4ItemType::LongLong => Some(MP4Data::LongLong(super::bridge::Item_toLongLong(
self.this.as_ref(),
))),
MP4ItemType::StringList => { MP4ItemType::StringList => {
let string_list = super::bridge::Item_toStringList(self.this.as_ref()); let string_list = super::bridge::Item_toStringList(self.this.as_ref());
let string_list_this = OwnedThis::new(string_list).unwrap(); let string_list_this = OwnedThis::new(string_list).unwrap();
Some(MP4Data::StringList(tk::StringList::new(string_list_this))) Some(MP4Data::StringList(tk::StringList::new(string_list_this)))
}, }
MP4ItemType::ByteVectorList => { MP4ItemType::ByteVectorList => {
let byte_vector_list = super::bridge::Item_toByteVectorList(self.this.as_ref()); let byte_vector_list = super::bridge::Item_toByteVectorList(self.this.as_ref());
let byte_vector_list_this = OwnedThis::new(byte_vector_list).unwrap(); let byte_vector_list_this = OwnedThis::new(byte_vector_list).unwrap();
Some(MP4Data::ByteVectorList(tk::ByteVectorList::new(byte_vector_list_this))) Some(MP4Data::ByteVectorList(tk::ByteVectorList::new(
}, byte_vector_list_this,
)))
}
MP4ItemType::CoverArtList => { MP4ItemType::CoverArtList => {
let cover_art_list = super::bridge::Item_toCoverArtList(self.this.as_ref()); let cover_art_list = super::bridge::Item_toCoverArtList(self.this.as_ref());
let cover_art_list_this = OwnedThis::new(cover_art_list).unwrap(); let cover_art_list_this = OwnedThis::new(cover_art_list).unwrap();
Some(MP4Data::CoverArtList(CoverArtList::new(cover_art_list_this))) Some(MP4Data::CoverArtList(CoverArtList::new(
cover_art_list_this,
)))
} }
}) })
} }

View file

@ -1,8 +1,7 @@
use super::bridge::{self, CPPMPEGFile}; use super::bridge::{CPPMPEGFile};
use super::id3v1::ID3v1Tag; use super::id3v1::ID3v1Tag;
use super::id3v2::ID3v2Tag; use super::id3v2::ID3v2Tag;
use super::this::{RefThisMut, This, ThisMut}; use super::this::{RefThisMut, ThisMut};
use std::pin::Pin;
pub struct MPEGFile<'file_ref> { pub struct MPEGFile<'file_ref> {
this: RefThisMut<'file_ref, CPPMPEGFile>, this: RefThisMut<'file_ref, CPPMPEGFile>,

View file

@ -1,7 +1,6 @@
pub use super::bridge::{CPPOpusFile, CPPVorbisFile}; pub use super::bridge::{CPPOpusFile, CPPVorbisFile};
use super::this::RefThisMut;
use super::xiph::XiphComment; use super::xiph::XiphComment;
use super::this::{RefThisMut, RefThis, This};
use std::pin::Pin;
pub struct VorbisFile<'file_ref> { pub struct VorbisFile<'file_ref> {
this: RefThisMut<'file_ref, CPPVorbisFile>, this: RefThisMut<'file_ref, CPPVorbisFile>,

View file

@ -1,7 +1,6 @@
use super::bridge::{self, CPPWAVFile}; use super::bridge::{CPPWAVFile};
use super::id3v2::ID3v2Tag; use super::id3v2::ID3v2Tag;
use super::this::{RefThisMut, This, ThisMut}; use super::this::RefThisMut;
use std::pin::Pin;
pub struct WAVFile<'file_ref> { pub struct WAVFile<'file_ref> {
this: RefThisMut<'file_ref, CPPWAVFile>, this: RefThisMut<'file_ref, CPPWAVFile>,

View file

@ -1,7 +1,7 @@
use super::bridge::{TagLibAllocated, TagLibRef, TagLibShared};
use cxx::{memory::UniquePtrTarget, UniquePtr};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::pin::Pin; use std::pin::Pin;
use cxx::{UniquePtr, memory::UniquePtrTarget};
use super::bridge::{TagLibAllocated, TagLibRef, TagLibShared};
/// A taglib-FFI-specific trait representing a C++ object returned by the library. /// A taglib-FFI-specific trait representing a C++ object returned by the library.
/// ///
@ -10,7 +10,7 @@ use super::bridge::{TagLibAllocated, TagLibRef, TagLibShared};
/// and will be dropped when the FileRef is dropped. /// and will be dropped when the FileRef is dropped.
/// - This object will not move or be mutated over the FileRef's lifetime, this way /// - This object will not move or be mutated over the FileRef's lifetime, this way
/// it can be temporarily pinned for use as a `this` pointer. /// it can be temporarily pinned for use as a `this` pointer.
pub trait This<'file_ref, T: TagLibAllocated> : AsRef<T> {} pub trait This<'file_ref, T: TagLibAllocated>: AsRef<T> {}
/// A taglib-FFI-specific trait representing a C++ object returned by the library. /// A taglib-FFI-specific trait representing a C++ object returned by the library.
/// ///
@ -22,13 +22,13 @@ pub trait This<'file_ref, T: TagLibAllocated> : AsRef<T> {}
/// and will be dropped when the FileRef is dropped. /// and will be dropped when the FileRef is dropped.
/// - This object will not move over the FileRef's lifetime, this way it can be /// - This object will not move over the FileRef's lifetime, this way it can be
/// temporarily pinned for use as a `this` pointer. /// temporarily pinned for use as a `this` pointer.
pub trait ThisMut<'file_ref, T: TagLibAllocated> : This<'file_ref, T> { pub trait ThisMut<'file_ref, T: TagLibAllocated>: This<'file_ref, T> {
fn pin_mut(&mut self) -> Pin<&mut T>; fn pin_mut(&mut self) -> Pin<&mut T>;
} }
/// A [This] instance that is a reference to a C++ object. /// A [This] instance that is a reference to a C++ object.
pub struct RefThis<'file_ref, T: TagLibRef> { pub struct RefThis<'file_ref, T: TagLibRef> {
this: &'file_ref T this: &'file_ref T,
} }
impl<'file_ref, T: TagLibRef> RefThis<'file_ref, T> { impl<'file_ref, T: TagLibRef> RefThis<'file_ref, T> {
@ -155,9 +155,10 @@ impl<'file_ref, T: TagLibShared + UniquePtrTarget> AsRef<T> for OwnedThis<'file_
impl<'file_ref, T: TagLibShared + UniquePtrTarget> This<'file_ref, T> for OwnedThis<'file_ref, T> {} impl<'file_ref, T: TagLibShared + UniquePtrTarget> This<'file_ref, T> for OwnedThis<'file_ref, T> {}
impl<'file_ref, T: TagLibShared + UniquePtrTarget> ThisMut<'file_ref, T> for OwnedThis<'file_ref, T> { impl<'file_ref, T: TagLibShared + UniquePtrTarget> ThisMut<'file_ref, T>
for OwnedThis<'file_ref, T>
{
fn pin_mut(&mut self) -> Pin<&mut T> { fn pin_mut(&mut self) -> Pin<&mut T> {
self.this.as_mut().unwrap() self.this.as_mut().unwrap()
} }
} }

View file

@ -1,14 +1,12 @@
use super::bridge; use super::bridge;
use super::this::{RefThis, RefThisMut, This, OwnedThis}; use super::this::{OwnedThis, RefThis, RefThisMut, This};
use cxx::{memory::UniquePtrTarget, UniquePtr};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::pin::Pin;
use std::{ffi::CStr, string::ToString}; use std::{ffi::CStr, string::ToString};
pub use bridge::CPPString as InnerString;
pub use bridge::CPPStringList as InnerStringList;
pub use bridge::CPPByteVector as InnerByteVector; pub use bridge::CPPByteVector as InnerByteVector;
pub use bridge::CPPByteVectorList as InnerByteVectorList; pub use bridge::CPPByteVectorList as InnerByteVectorList;
pub use bridge::CPPString as InnerString;
pub use bridge::CPPStringList as InnerStringList;
pub struct String<'file_ref, T: This<'file_ref, InnerString>> { pub struct String<'file_ref, T: This<'file_ref, InnerString>> {
_data: PhantomData<&'file_ref ()>, _data: PhantomData<&'file_ref ()>,
@ -17,7 +15,10 @@ pub struct String<'file_ref, T: This<'file_ref, InnerString>> {
impl<'file_ref, T: This<'file_ref, InnerString>> String<'file_ref, T> { impl<'file_ref, T: This<'file_ref, InnerString>> String<'file_ref, T> {
pub(super) fn new(this: T) -> Self { pub(super) fn new(this: T) -> Self {
Self { _data: PhantomData, this } Self {
_data: PhantomData,
this,
}
} }
} }
@ -49,13 +50,12 @@ pub struct StringList<'file_ref, T: This<'file_ref, InnerStringList>> {
this: T, this: T,
} }
pub type OwnedStringList<'file_ref> = StringList<'file_ref, OwnedThis<'file_ref, InnerStringList>>;
pub type RefStringList<'file_ref> = StringList<'file_ref, RefThis<'file_ref, InnerStringList>>;
pub type RefStringListMut<'file_ref> = StringList<'file_ref, RefThisMut<'file_ref, InnerStringList>>;
impl<'file_ref, T: This<'file_ref, InnerStringList>> StringList<'file_ref, T> { impl<'file_ref, T: This<'file_ref, InnerStringList>> StringList<'file_ref, T> {
pub(super) fn new(this: T) -> Self { pub(super) fn new(this: T) -> Self {
Self { _data: PhantomData, this } Self {
_data: PhantomData,
this,
}
} }
pub fn to_vec(&self) -> Vec<std::string::String> { pub fn to_vec(&self) -> Vec<std::string::String> {
@ -70,6 +70,11 @@ impl<'file_ref, T: This<'file_ref, InnerStringList>> StringList<'file_ref, T> {
} }
} }
pub type OwnedStringList<'file_ref> = StringList<'file_ref, OwnedThis<'file_ref, InnerStringList>>;
pub type RefStringList<'file_ref> = StringList<'file_ref, RefThis<'file_ref, InnerStringList>>;
pub type RefStringListMut<'file_ref> =
StringList<'file_ref, RefThisMut<'file_ref, InnerStringList>>;
pub struct ByteVector<'file_ref, T: This<'file_ref, InnerByteVector>> { pub struct ByteVector<'file_ref, T: This<'file_ref, InnerByteVector>> {
_data: PhantomData<&'file_ref InnerByteVector>, _data: PhantomData<&'file_ref InnerByteVector>,
this: T, this: T,
@ -77,7 +82,10 @@ pub struct ByteVector<'file_ref, T: This<'file_ref, InnerByteVector>> {
impl<'file_ref, T: This<'file_ref, InnerByteVector>> ByteVector<'file_ref, T> { impl<'file_ref, T: This<'file_ref, InnerByteVector>> ByteVector<'file_ref, T> {
pub(super) fn new(this: T) -> Self { pub(super) fn new(this: T) -> Self {
Self { _data: PhantomData, this } Self {
_data: PhantomData,
this,
}
} }
pub fn to_vec(&self) -> Vec<u8> { pub fn to_vec(&self) -> Vec<u8> {
@ -107,7 +115,8 @@ impl<'file_ref, T: This<'file_ref, InnerByteVector>> ByteVector<'file_ref, T> {
pub type OwnedByteVector<'file_ref> = ByteVector<'file_ref, OwnedThis<'file_ref, InnerByteVector>>; pub type OwnedByteVector<'file_ref> = ByteVector<'file_ref, OwnedThis<'file_ref, InnerByteVector>>;
pub type RefByteVector<'file_ref> = ByteVector<'file_ref, RefThis<'file_ref, InnerByteVector>>; pub type RefByteVector<'file_ref> = ByteVector<'file_ref, RefThis<'file_ref, InnerByteVector>>;
pub type RefByteVectorMut<'file_ref> = ByteVector<'file_ref, RefThisMut<'file_ref, InnerByteVector>>; pub type RefByteVectorMut<'file_ref> =
ByteVector<'file_ref, RefThisMut<'file_ref, InnerByteVector>>;
pub struct ByteVectorList<'file_ref, T: This<'file_ref, InnerByteVectorList>> { pub struct ByteVectorList<'file_ref, T: This<'file_ref, InnerByteVectorList>> {
_data: PhantomData<&'file_ref InnerByteVectorList>, _data: PhantomData<&'file_ref InnerByteVectorList>,
@ -116,7 +125,10 @@ pub struct ByteVectorList<'file_ref, T: This<'file_ref, InnerByteVectorList>> {
impl<'file_ref, T: This<'file_ref, InnerByteVectorList>> ByteVectorList<'file_ref, T> { impl<'file_ref, T: This<'file_ref, InnerByteVectorList>> ByteVectorList<'file_ref, T> {
pub(super) fn new(this: T) -> Self { pub(super) fn new(this: T) -> Self {
Self { _data: PhantomData, this } Self {
_data: PhantomData,
this,
}
} }
pub fn to_vec(&self) -> Vec<Vec<u8>> { pub fn to_vec(&self) -> Vec<Vec<u8>> {
@ -128,7 +140,9 @@ impl<'file_ref, T: This<'file_ref, InnerByteVectorList>> ByteVectorList<'file_re
} }
} }
pub type OwnedByteVectorList<'file_ref> = ByteVectorList<'file_ref, OwnedThis<'file_ref, InnerByteVectorList>>; pub type OwnedByteVectorList<'file_ref> =
pub type RefByteVectorList<'file_ref> = ByteVectorList<'file_ref, RefThis<'file_ref, InnerByteVectorList>>; ByteVectorList<'file_ref, OwnedThis<'file_ref, InnerByteVectorList>>;
pub type RefByteVectorListMut<'file_ref> = ByteVectorList<'file_ref, RefThisMut<'file_ref, InnerByteVectorList>>; pub type RefByteVectorList<'file_ref> =
ByteVectorList<'file_ref, RefThis<'file_ref, InnerByteVectorList>>;
pub type RefByteVectorListMut<'file_ref> =
ByteVectorList<'file_ref, RefThisMut<'file_ref, InnerByteVectorList>>;

View file

@ -1,10 +1,9 @@
pub use super::bridge::CPPXiphComment; pub use super::bridge::CPPXiphComment;
use super::bridge::{CPPFieldListMap, FieldListMap_to_entries, XiphComment_pictureList}; use super::bridge::{CPPFieldListMap, FieldListMap_to_entries, XiphComment_pictureList};
pub use super::flac::PictureList; pub use super::flac::PictureList;
use super::this::{OwnedThis, RefThis, RefThisMut, ThisMut};
use super::tk; use super::tk;
use super::this::{OwnedThis, RefThis, RefThisMut, ThisMut, This};
use std::collections::HashMap; use std::collections::HashMap;
use std::pin::Pin;
pub struct XiphComment<'file_ref> { pub struct XiphComment<'file_ref> {
this: RefThisMut<'file_ref, CPPXiphComment>, this: RefThisMut<'file_ref, CPPXiphComment>,

View file

@ -1,7 +1,10 @@
use jni::{
objects::{JObject, JValueGen},
JNIEnv,
};
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell;
use jni::{objects::{JObject, JValueGen}, JNIEnv};
pub struct JTagMap<'local> { pub struct JTagMap<'local> {
env: Rc<RefCell<JNIEnv<'local>>>, env: Rc<RefCell<JNIEnv<'local>>>,
@ -27,7 +30,12 @@ impl<'local> JTagMap<'local> {
self.map.entry(id).or_default().extend(values); self.map.entry(id).or_default().extend(values);
} }
pub fn add_combined(&mut self, id: impl Into<String>, description: impl Into<String>, value: impl Into<String>) { pub fn add_combined(
&mut self,
id: impl Into<String>,
description: impl Into<String>,
value: impl Into<String>,
) {
let id = id.into(); let id = id.into();
let description = description.into(); let description = description.into();
let value = value.into(); let value = value.into();
@ -36,8 +44,16 @@ impl<'local> JTagMap<'local> {
} }
pub fn get_object(&self) -> JObject { pub fn get_object(&self) -> JObject {
let map_class = self.env.borrow_mut().find_class("java/util/HashMap").unwrap(); let map_class = self
let map = self.env.borrow_mut().new_object(&map_class, "()V", &[]).unwrap(); .env
.borrow_mut()
.find_class("java/util/HashMap")
.unwrap();
let map = self
.env
.borrow_mut()
.new_object(&map_class, "()V", &[])
.unwrap();
for (key, values) in &self.map { for (key, values) in &self.map {
let j_key = self.env.borrow().new_string(key).unwrap(); let j_key = self.env.borrow().new_string(key).unwrap();
@ -47,26 +63,38 @@ impl<'local> JTagMap<'local> {
.collect(); .collect();
// Create ArrayList for values // Create ArrayList for values
let array_list_class = self.env.borrow_mut().find_class("java/util/ArrayList").unwrap(); let array_list_class = self
let array_list = self.env.borrow_mut().new_object(array_list_class, "()V", &[]).unwrap(); .env
.borrow_mut()
.find_class("java/util/ArrayList")
.unwrap();
let array_list = self
.env
.borrow_mut()
.new_object(array_list_class, "()V", &[])
.unwrap();
for value in j_values { for value in j_values {
self.env.borrow_mut() self.env
.borrow_mut()
.call_method( .call_method(
&array_list, &array_list,
"add", "add",
"(Ljava/lang/Object;)Z", "(Ljava/lang/Object;)Z",
&[JValueGen::from(&value)] &[JValueGen::from(&value)],
).unwrap(); )
.unwrap();
} }
self.env.borrow_mut() self.env
.borrow_mut()
.call_method( .call_method(
&map, &map,
"put", "put",
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
&[JValueGen::from(&j_key), JValueGen::from(&array_list)] &[JValueGen::from(&j_key), JValueGen::from(&array_list)],
).unwrap(); )
.unwrap();
} }
map map