diff --git a/build.gradle b/build.gradle index 9e8ccd337..049c1a542 100644 --- a/build.gradle +++ b/build.gradle @@ -43,8 +43,8 @@ spotless { } cpp { - target "*/src/**/cpp/*.cpp" - eclipseCdt() + target("*/src/**/cpp/*.cpp", "*/src/**/cpp/*.h", "*/src/**/cpp/*.hpp") + eclipseCdt().configFile("eclipse-cdt.xml") licenseHeaderFile("NOTICE") } } diff --git a/eclipse-cdt.xml b/eclipse-cdt.xml new file mode 100644 index 000000000..4e6c20576 --- /dev/null +++ b/eclipse-cdt.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/musikr/src/main/AndroidManifest.xml b/musikr/src/main/AndroidManifest.xml index a5918e68a..5a898a4a2 100644 --- a/musikr/src/main/AndroidManifest.xml +++ b/musikr/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ - + \ No newline at end of file diff --git a/musikr/src/main/cpp/JVMInputStream.cpp b/musikr/src/main/cpp/JVMInputStream.cpp index 823b77ed7..0ede3272d 100644 --- a/musikr/src/main/cpp/JVMInputStream.cpp +++ b/musikr/src/main/cpp/JVMInputStream.cpp @@ -22,102 +22,102 @@ // TODO: Handle stream exceptions JVMInputStream::JVMInputStream(JNIEnv *env, jobject inputStream) : env(env), inputStream( - inputStream) { - if (!env->IsInstanceOf(inputStream, - env->FindClass("org/oxycblt/musikr/metadata/NativeInputStream"))) { - throw std::runtime_error("oStream is not an instance of TagLibOStream"); - } - jclass inputStreamClass = env->FindClass( - "org/oxycblt/musikr/metadata/NativeInputStream"); - inputStreamReadBlockMethod = env->GetMethodID(inputStreamClass, "readBlock", - "(J)[B"); - inputStreamIsOpenMethod = env->GetMethodID(inputStreamClass, "isOpen", - "()Z"); - inputStreamSeekFromBeginningMethod = env->GetMethodID(inputStreamClass, - "seekFromBeginning", "(J)V"); - inputStreamSeekFromCurrentMethod = env->GetMethodID(inputStreamClass, - "seekFromCurrent", "(J)V"); - inputStreamSeekFromEndMethod = env->GetMethodID(inputStreamClass, - "seekFromEnd", "(J)V"); - inputStreamTellMethod = env->GetMethodID(inputStreamClass, "tell", "()J"); - inputStreamLengthMethod = env->GetMethodID(inputStreamClass, "length", - "()J"); - env->DeleteLocalRef(inputStreamClass); + inputStream) { + if (!env->IsInstanceOf(inputStream, + env->FindClass("org/oxycblt/musikr/metadata/NativeInputStream"))) { + throw std::runtime_error("oStream is not an instance of TagLibOStream"); + } + jclass inputStreamClass = env->FindClass( + "org/oxycblt/musikr/metadata/NativeInputStream"); + inputStreamReadBlockMethod = env->GetMethodID(inputStreamClass, "readBlock", + "(J)[B"); + inputStreamIsOpenMethod = env->GetMethodID(inputStreamClass, "isOpen", + "()Z"); + inputStreamSeekFromBeginningMethod = env->GetMethodID(inputStreamClass, + "seekFromBeginning", "(J)V"); + inputStreamSeekFromCurrentMethod = env->GetMethodID(inputStreamClass, + "seekFromCurrent", "(J)V"); + inputStreamSeekFromEndMethod = env->GetMethodID(inputStreamClass, + "seekFromEnd", "(J)V"); + inputStreamTellMethod = env->GetMethodID(inputStreamClass, "tell", "()J"); + inputStreamLengthMethod = env->GetMethodID(inputStreamClass, "length", + "()J"); + env->DeleteLocalRef(inputStreamClass); } JVMInputStream::~JVMInputStream() { - // The implicit assumption is that inputStream is managed by the owner, - // so we don't need to delete any references here + // The implicit assumption is that inputStream is managed by the owner, + // so we don't need to delete any references here } TagLib::FileName JVMInputStream::name() const { - // Not actually used except in FileRef, can safely ignore. - return ""; + // Not actually used except in FileRef, can safely ignore. + return ""; } TagLib::ByteVector JVMInputStream::readBlock(size_t length) { - auto data = (jbyteArray) env->CallObjectMethod(inputStream, - inputStreamReadBlockMethod, length); - jsize dataLength = env->GetArrayLength(data); - auto dataBytes = env->GetByteArrayElements(data, nullptr); - TagLib::ByteVector byteVector(reinterpret_cast(dataBytes), - dataLength); - env->ReleaseByteArrayElements(data, dataBytes, JNI_ABORT); - return byteVector; + auto data = (jbyteArray) env->CallObjectMethod(inputStream, + inputStreamReadBlockMethod, length); + jsize dataLength = env->GetArrayLength(data); + auto dataBytes = env->GetByteArrayElements(data, nullptr); + TagLib::ByteVector byteVector(reinterpret_cast(dataBytes), + dataLength); + env->ReleaseByteArrayElements(data, dataBytes, JNI_ABORT); + return byteVector; } void JVMInputStream::writeBlock(const TagLib::ByteVector &data) { - throw std::runtime_error("Not implemented"); + throw std::runtime_error("Not implemented"); } void JVMInputStream::insert(const TagLib::ByteVector &data, - TagLib::offset_t start, size_t replace) { - throw std::runtime_error("Not implemented"); + TagLib::offset_t start, size_t replace) { + throw std::runtime_error("Not implemented"); } void JVMInputStream::removeBlock(TagLib::offset_t start, size_t length) { - throw std::runtime_error("Not implemented"); + throw std::runtime_error("Not implemented"); } bool JVMInputStream::readOnly() const { - return true; + return true; } bool JVMInputStream::isOpen() const { - return env->CallBooleanMethod(inputStream, inputStreamIsOpenMethod); + return env->CallBooleanMethod(inputStream, inputStreamIsOpenMethod); } void JVMInputStream::seek(TagLib::offset_t offset, Position p) { - auto joffset = static_cast(std::llround(offset)); - switch (p) { - case Beginning: - env->CallVoidMethod(inputStream, inputStreamSeekFromBeginningMethod, - joffset); - break; - case Current: - env->CallVoidMethod(inputStream, inputStreamSeekFromCurrentMethod, - joffset); - break; - case End: - env->CallVoidMethod(inputStream, inputStreamSeekFromEndMethod, joffset); - break; - } + auto joffset = static_cast(std::llround(offset)); + switch (p) { + case Beginning: + env->CallVoidMethod(inputStream, inputStreamSeekFromBeginningMethod, + joffset); + break; + case Current: + env->CallVoidMethod(inputStream, inputStreamSeekFromCurrentMethod, + joffset); + break; + case End: + env->CallVoidMethod(inputStream, inputStreamSeekFromEndMethod, joffset); + break; + } } void JVMInputStream::clear() { - // Nothing to do + // Nothing to do } TagLib::offset_t JVMInputStream::tell() const { - jlong jposition = env->CallLongMethod(inputStream, inputStreamTellMethod); - return static_cast(jposition); + jlong jposition = env->CallLongMethod(inputStream, inputStreamTellMethod); + return static_cast(jposition); } TagLib::offset_t JVMInputStream::length() { - jlong jlength = env->CallLongMethod(inputStream, inputStreamLengthMethod); - return static_cast(jlength); + jlong jlength = env->CallLongMethod(inputStream, inputStreamLengthMethod); + return static_cast(jlength); } void JVMInputStream::truncate(TagLib::offset_t length) { - throw std::runtime_error("Not implemented"); + throw std::runtime_error("Not implemented"); } diff --git a/musikr/src/main/cpp/JVMInputStream.h b/musikr/src/main/cpp/JVMInputStream.h index 8007535c5..f89e39d3b 100644 --- a/musikr/src/main/cpp/JVMInputStream.h +++ b/musikr/src/main/cpp/JVMInputStream.h @@ -1,7 +1,21 @@ -// -// Created by oxycblt on 12/12/24. -// - +/* + * Copyright (c) 2024 Auxio Project + * JVMInputStream.h is part of Auxio. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef AUXIO_JVMINPUTSTREAM_H #define AUXIO_JVMINPUTSTREAM_H @@ -9,14 +23,14 @@ #include "taglib/tiostream.h" -class JVMInputStream : public TagLib::IOStream { +class JVMInputStream: public TagLib::IOStream { public: JVMInputStream(JNIEnv *env, jobject inputStream); ~JVMInputStream(); - JVMInputStream(const JVMInputStream &) = delete; - JVMInputStream &operator=(const JVMInputStream &) = delete; + JVMInputStream(const JVMInputStream&) = delete; + JVMInputStream& operator=(const JVMInputStream&) = delete; /*! * Returns the stream name in the local file system encoding. @@ -46,8 +60,8 @@ public: * \note This method is slow since it requires rewriting all of the file * after the insertion point. */ - void insert(const TagLib::ByteVector &data, - TagLib::offset_t start = 0, size_t replace = 0) override; + void insert(const TagLib::ByteVector &data, TagLib::offset_t start = 0, + size_t replace = 0) override; /*! * Removes a block of the file starting a \a start and continuing for @@ -110,5 +124,4 @@ private: }; - #endif //AUXIO_JVMINPUTSTREAM_H diff --git a/musikr/src/main/cpp/JVMMetadataBuilder.cpp b/musikr/src/main/cpp/JVMMetadataBuilder.cpp index d335745cf..1db08a59d 100644 --- a/musikr/src/main/cpp/JVMMetadataBuilder.cpp +++ b/musikr/src/main/cpp/JVMMetadataBuilder.cpp @@ -26,142 +26,142 @@ #include JVMMetadataBuilder::JVMMetadataBuilder(JNIEnv *env) : env(env), id3v2(env), xiph( - env), mp4(env), cover(), properties(nullptr) { + env), mp4(env), cover(), properties(nullptr) { } void JVMMetadataBuilder::setMimeType(const std::string_view type) { - this->mimeType = type; + this->mimeType = type; } void JVMMetadataBuilder::setId3v2(const TagLib::ID3v2::Tag &tag) { - for (auto frame : tag.frameList()) { - if (auto txxxFrame = - dynamic_cast(frame)) { - TagLib::StringList frameText = txxxFrame->fieldList(); - // Frame text starts with the description then the remaining values - auto begin = frameText.begin(); - TagLib::String key = TagLib::String(frame->frameID()) + ":" - + begin->upper(); - frameText.erase(begin); - id3v2.add(key, frameText); - } else if (auto textFrame = - dynamic_cast(frame)) { - TagLib::String key = frame->frameID(); - TagLib::StringList frameText = textFrame->fieldList(); - id3v2.add(key, frameText); - } else { - continue; - } - } + for (auto frame : tag.frameList()) { + if (auto txxxFrame = + dynamic_cast(frame)) { + TagLib::StringList frameText = txxxFrame->fieldList(); + // Frame text starts with the description then the remaining values + auto begin = frameText.begin(); + TagLib::String key = TagLib::String(frame->frameID()) + ":" + + begin->upper(); + frameText.erase(begin); + id3v2.add(key, frameText); + } else if (auto textFrame = + dynamic_cast(frame)) { + TagLib::String key = frame->frameID(); + TagLib::StringList frameText = textFrame->fieldList(); + id3v2.add(key, frameText); + } else { + continue; + } + } } void JVMMetadataBuilder::setXiph(const TagLib::Ogg::XiphComment &tag) { - for (auto field : tag.fieldListMap()) { - auto key = field.first.upper(); - auto values = field.second; - xiph.add(key, values); - } + for (auto field : tag.fieldListMap()) { + auto key = field.first.upper(); + auto values = field.second; + xiph.add(key, values); + } } void JVMMetadataBuilder::setMp4(const TagLib::MP4::Tag &tag) { - auto map = tag.itemMap(); - for (auto item : map) { - auto itemName = item.first; - if (itemName.startsWith("----")) { - // Capitalize description atoms only - // Other standard atoms are cased so we want to avoid collissions there. - itemName = itemName.upper(); - } - auto itemValue = item.second; - auto type = itemValue.type(); - // Only read out the atoms for the reasonable tags we are expecting. - // None of the crazy binary atoms. - if (type == TagLib::MP4::Item::Type::StringList) { - auto value = itemValue.toStringList(); - mp4.add(itemName, value); - continue; - } + auto map = tag.itemMap(); + for (auto item : map) { + auto itemName = item.first; + if (itemName.startsWith("----")) { + // Capitalize description atoms only + // Other standard atoms are cased so we want to avoid collissions there. + itemName = itemName.upper(); + } + auto itemValue = item.second; + auto type = itemValue.type(); + // Only read out the atoms for the reasonable tags we are expecting. + // None of the crazy binary atoms. + if (type == TagLib::MP4::Item::Type::StringList) { + auto value = itemValue.toStringList(); + mp4.add(itemName, value); + continue; + } - // Assume that taggers will be unhinged and store track numbers - // as ints, uints, or longs. - if (type == TagLib::MP4::Item::Type::Int) { - auto value = std::to_string(itemValue.toInt()); - id3v2.add(itemName, value); - continue; - } - if (type == TagLib::MP4::Item::Type::UInt) { - auto value = std::to_string(itemValue.toUInt()); - id3v2.add(itemName, value); - continue; - } - if (type == TagLib::MP4::Item::Type::LongLong) { - auto value = std::to_string(itemValue.toLongLong()); - id3v2.add(itemName, value); - continue; - } - if (type == TagLib::MP4::Item::Type::IntPair) { - // It's inefficient going from the integer representation back into - // a string, but I fully expect taggers to just write "NN/TT" strings - // anyway, and musikr doesn't have to do as much fiddly variant handling. - auto value = std::to_string(itemValue.toIntPair().first) + "/" - + std::to_string(itemValue.toIntPair().second); - id3v2.add(itemName, value); - continue; - } - } + // Assume that taggers will be unhinged and store track numbers + // as ints, uints, or longs. + if (type == TagLib::MP4::Item::Type::Int) { + auto value = std::to_string(itemValue.toInt()); + id3v2.add(itemName, value); + continue; + } + if (type == TagLib::MP4::Item::Type::UInt) { + auto value = std::to_string(itemValue.toUInt()); + id3v2.add(itemName, value); + continue; + } + if (type == TagLib::MP4::Item::Type::LongLong) { + auto value = std::to_string(itemValue.toLongLong()); + id3v2.add(itemName, value); + continue; + } + if (type == TagLib::MP4::Item::Type::IntPair) { + // It's inefficient going from the integer representation back into + // a string, but I fully expect taggers to just write "NN/TT" strings + // anyway, and musikr doesn't have to do as much fiddly variant handling. + auto value = std::to_string(itemValue.toIntPair().first) + "/" + + std::to_string(itemValue.toIntPair().second); + id3v2.add(itemName, value); + continue; + } + } } void JVMMetadataBuilder::setCover( - const TagLib::List covers) { - if (covers.isEmpty()) { - return; - } - // Find the cover with a "front cover" type - for (auto cover : covers) { - auto type = cover["pictureType"].toString(); - if (type == "Front Cover") { - this->cover = cover["data"].toByteVector(); - return; - } - } - // No front cover, just pick first. - // TODO: Consider having cascading fallbacks to increasingly less - // relevant covers perhaps - this->cover = covers.front()["data"].toByteVector(); + const TagLib::List covers) { + if (covers.isEmpty()) { + return; + } + // Find the cover with a "front cover" type + for (auto cover : covers) { + auto type = cover["pictureType"].toString(); + if (type == "Front Cover") { + this->cover = cover["data"].toByteVector(); + return; + } + } + // No front cover, just pick first. + // TODO: Consider having cascading fallbacks to increasingly less + // relevant covers perhaps + this->cover = covers.front()["data"].toByteVector(); } void JVMMetadataBuilder::setProperties(TagLib::AudioProperties *properties) { - this->properties = properties; + this->properties = properties; } jobject JVMMetadataBuilder::build() { - jclass propertiesClass = env->FindClass( - "org/oxycblt/musikr/metadata/Properties"); - jmethodID propertiesInit = env->GetMethodID(propertiesClass, "", - "(Ljava/lang/String;JII)V"); - jobject propertiesObj = env->NewObject(propertiesClass, propertiesInit, - env->NewStringUTF(mimeType.data()), - (jlong) properties->lengthInMilliseconds(), properties->bitrate(), - properties->sampleRate()); - env->DeleteLocalRef(propertiesClass); + jclass propertiesClass = env->FindClass( + "org/oxycblt/musikr/metadata/Properties"); + jmethodID propertiesInit = env->GetMethodID(propertiesClass, "", + "(Ljava/lang/String;JII)V"); + jobject propertiesObj = env->NewObject(propertiesClass, propertiesInit, + env->NewStringUTF(mimeType.data()), + (jlong) properties->lengthInMilliseconds(), properties->bitrate(), + properties->sampleRate()); + env->DeleteLocalRef(propertiesClass); - jclass metadataClass = env->FindClass( - "org/oxycblt/musikr/metadata/Metadata"); - jmethodID metadataInit = env->GetMethodID(metadataClass, "", - "(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;[BLorg/" - "oxycblt/musikr/metadata/Properties;)V"); - jobject id3v2Map = id3v2.getObject(); - jobject xiphMap = xiph.getObject(); - jobject mp4Map = mp4.getObject(); - jbyteArray coverArray = nullptr; - if (cover.has_value()) { - auto coverSize = static_cast(cover->size()); - coverArray = env->NewByteArray(coverSize); - env->SetByteArrayRegion(coverArray, 0, coverSize, - reinterpret_cast(cover->data())); - } - jobject metadataObj = env->NewObject(metadataClass, metadataInit, id3v2Map, - xiphMap, mp4Map, coverArray, propertiesObj); - env->DeleteLocalRef(metadataClass); - return metadataObj; + jclass metadataClass = env->FindClass( + "org/oxycblt/musikr/metadata/Metadata"); + jmethodID metadataInit = env->GetMethodID(metadataClass, "", + "(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;[BLorg/" + "oxycblt/musikr/metadata/Properties;)V"); + jobject id3v2Map = id3v2.getObject(); + jobject xiphMap = xiph.getObject(); + jobject mp4Map = mp4.getObject(); + jbyteArray coverArray = nullptr; + if (cover.has_value()) { + auto coverSize = static_cast(cover->size()); + coverArray = env->NewByteArray(coverSize); + env->SetByteArrayRegion(coverArray, 0, coverSize, + reinterpret_cast(cover->data())); + } + jobject metadataObj = env->NewObject(metadataClass, metadataInit, id3v2Map, + xiphMap, mp4Map, coverArray, propertiesObj); + env->DeleteLocalRef(metadataClass); + return metadataObj; } diff --git a/musikr/src/main/cpp/JVMMetadataBuilder.h b/musikr/src/main/cpp/JVMMetadataBuilder.h index 4ad34f524..df2a7f8bf 100644 --- a/musikr/src/main/cpp/JVMMetadataBuilder.h +++ b/musikr/src/main/cpp/JVMMetadataBuilder.h @@ -1,7 +1,21 @@ -// -// Created by oxycblt on 12/12/24. -// - +/* + * Copyright (c) 2024 Auxio Project + * JVMMetadataBuilder.h is part of Auxio. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef AUXIO_JVMMETADATABUILDER_H #define AUXIO_JVMMETADATABUILDER_H diff --git a/musikr/src/main/cpp/JVMTagMap.cpp b/musikr/src/main/cpp/JVMTagMap.cpp index e5eb25fc4..70bfe342d 100644 --- a/musikr/src/main/cpp/JVMTagMap.cpp +++ b/musikr/src/main/cpp/JVMTagMap.cpp @@ -19,75 +19,75 @@ #include "JVMTagMap.h" JVMTagMap::JVMTagMap(JNIEnv *env) : env(env) { - jclass hashMapClass = env->FindClass("java/util/HashMap"); - jmethodID init = env->GetMethodID(hashMapClass, "", "()V"); - hashMap = env->NewObject(hashMapClass, init); - hashMapGetMethod = env->GetMethodID(hashMapClass, "get", - "(Ljava/lang/Object;)Ljava/lang/Object;"); - hashMapPutMethod = env->GetMethodID(hashMapClass, "put", - "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); - env->DeleteLocalRef(hashMapClass); + jclass hashMapClass = env->FindClass("java/util/HashMap"); + jmethodID init = env->GetMethodID(hashMapClass, "", "()V"); + hashMap = env->NewObject(hashMapClass, init); + hashMapGetMethod = env->GetMethodID(hashMapClass, "get", + "(Ljava/lang/Object;)Ljava/lang/Object;"); + hashMapPutMethod = env->GetMethodID(hashMapClass, "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + env->DeleteLocalRef(hashMapClass); - jclass arrayListClass = env->FindClass("java/util/ArrayList"); - arrayListInitMethod = env->GetMethodID(arrayListClass, "", "()V"); - arrayListAddMethod = env->GetMethodID(arrayListClass, "add", - "(Ljava/lang/Object;)Z"); - env->DeleteLocalRef(arrayListClass); + jclass arrayListClass = env->FindClass("java/util/ArrayList"); + arrayListInitMethod = env->GetMethodID(arrayListClass, "", "()V"); + arrayListAddMethod = env->GetMethodID(arrayListClass, "add", + "(Ljava/lang/Object;)Z"); + env->DeleteLocalRef(arrayListClass); } JVMTagMap::~JVMTagMap() { - env->DeleteLocalRef(hashMap); + env->DeleteLocalRef(hashMap); } void JVMTagMap::add(TagLib::String &key, std::string_view value) { - jstring jKey = env->NewStringUTF(key.toCString(true)); - jstring jValue = env->NewStringUTF(value.data()); + jstring jKey = env->NewStringUTF(key.toCString(true)); + jstring jValue = env->NewStringUTF(value.data()); - // check if theres already a value arraylist in the map - jobject existingValue = env->CallObjectMethod(hashMap, hashMapGetMethod, - jKey); - // if there is, add to the value to the existing arraylist - if (existingValue != nullptr) { - env->CallBooleanMethod(existingValue, arrayListAddMethod, jValue); - } else { - // if there isn't, create a new arraylist and add the value to it - jclass arrayListClass = env->FindClass("java/util/ArrayList"); - jobject arrayList = env->NewObject(arrayListClass, arrayListInitMethod); - env->CallBooleanMethod(arrayList, arrayListAddMethod, jValue); - env->CallObjectMethod(hashMap, hashMapPutMethod, jKey, arrayList); - env->DeleteLocalRef(arrayListClass); - } + // check if theres already a value arraylist in the map + jobject existingValue = env->CallObjectMethod(hashMap, hashMapGetMethod, + jKey); + // if there is, add to the value to the existing arraylist + if (existingValue != nullptr) { + env->CallBooleanMethod(existingValue, arrayListAddMethod, jValue); + } else { + // if there isn't, create a new arraylist and add the value to it + jclass arrayListClass = env->FindClass("java/util/ArrayList"); + jobject arrayList = env->NewObject(arrayListClass, arrayListInitMethod); + env->CallBooleanMethod(arrayList, arrayListAddMethod, jValue); + env->CallObjectMethod(hashMap, hashMapPutMethod, jKey, arrayList); + env->DeleteLocalRef(arrayListClass); + } } void JVMTagMap::add(TagLib::String &key, TagLib::StringList &value) { - if (value.isEmpty()) { - // Nothing to add - return; - } - jstring jKey = env->NewStringUTF(key.toCString(true)); + if (value.isEmpty()) { + // Nothing to add + return; + } + jstring jKey = env->NewStringUTF(key.toCString(true)); - // check if theres already a value arraylist in the map - jobject existingValue = env->CallObjectMethod(hashMap, hashMapGetMethod, - jKey); - // if there is, add to the value to the existing arraylist - if (existingValue != nullptr) { - for (auto &val : value) { - jstring jValue = env->NewStringUTF(val.toCString(true)); - env->CallBooleanMethod(existingValue, arrayListAddMethod, jValue); - } - } else { - // if there isn't, create a new arraylist and add the value to it - jclass arrayListClass = env->FindClass("java/util/ArrayList"); - jobject arrayList = env->NewObject(arrayListClass, arrayListInitMethod); - for (auto &val : value) { - jstring jValue = env->NewStringUTF(val.toCString(true)); - env->CallBooleanMethod(arrayList, arrayListAddMethod, jValue); - } - env->CallObjectMethod(hashMap, hashMapPutMethod, jKey, arrayList); - env->DeleteLocalRef(arrayListClass); - } + // check if theres already a value arraylist in the map + jobject existingValue = env->CallObjectMethod(hashMap, hashMapGetMethod, + jKey); + // if there is, add to the value to the existing arraylist + if (existingValue != nullptr) { + for (auto &val : value) { + jstring jValue = env->NewStringUTF(val.toCString(true)); + env->CallBooleanMethod(existingValue, arrayListAddMethod, jValue); + } + } else { + // if there isn't, create a new arraylist and add the value to it + jclass arrayListClass = env->FindClass("java/util/ArrayList"); + jobject arrayList = env->NewObject(arrayListClass, arrayListInitMethod); + for (auto &val : value) { + jstring jValue = env->NewStringUTF(val.toCString(true)); + env->CallBooleanMethod(arrayList, arrayListAddMethod, jValue); + } + env->CallObjectMethod(hashMap, hashMapPutMethod, jKey, arrayList); + env->DeleteLocalRef(arrayListClass); + } } jobject JVMTagMap::getObject() { - return hashMap; + return hashMap; } diff --git a/musikr/src/main/cpp/JVMTagMap.h b/musikr/src/main/cpp/JVMTagMap.h index a2cba8d45..3090730bb 100644 --- a/musikr/src/main/cpp/JVMTagMap.h +++ b/musikr/src/main/cpp/JVMTagMap.h @@ -1,7 +1,21 @@ -// -// Created by oxycblt on 12/12/24. -// - +/* + * Copyright (c) 2024 Auxio Project + * JVMTagMap.h is part of Auxio. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef AUXIO_JVMTAGMAP_H #define AUXIO_JVMTAGMAP_H @@ -15,8 +29,8 @@ public: JVMTagMap(JNIEnv *env); ~JVMTagMap(); - JVMTagMap(const JVMTagMap &) = delete; - JVMTagMap &operator=(const JVMTagMap &) = delete; + JVMTagMap(const JVMTagMap&) = delete; + JVMTagMap& operator=(const JVMTagMap&) = delete; void add(TagLib::String &key, std::string_view value); void add(TagLib::String &key, TagLib::StringList &value); @@ -32,5 +46,4 @@ private: jmethodID arrayListAddMethod; }; - #endif //AUXIO_JVMTAGMAP_H diff --git a/musikr/src/main/cpp/log.h b/musikr/src/main/cpp/log.h index c11d3cec0..2be505c6a 100644 --- a/musikr/src/main/cpp/log.h +++ b/musikr/src/main/cpp/log.h @@ -1,7 +1,21 @@ -// -// Created by oxycblt on 12/23/24. -// - +/* + * Copyright (c) 2024 Auxio Project + * log.h is part of Auxio. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #ifndef AUXIO_LOG_H #define AUXIO_LOG_H diff --git a/musikr/src/main/cpp/taglib_jni.cpp b/musikr/src/main/cpp/taglib_jni.cpp index 5eda71467..e8fca822c 100644 --- a/musikr/src/main/cpp/taglib_jni.cpp +++ b/musikr/src/main/cpp/taglib_jni.cpp @@ -32,48 +32,48 @@ extern "C" JNIEXPORT jobject JNICALL Java_org_oxycblt_musikr_metadata_TagLibJNI_openNative(JNIEnv *env, - jobject /* this */, - jobject inputStream) { - try { - JVMInputStream stream {env, inputStream}; - TagLib::FileRef fileRef {&stream}; - if (fileRef.isNull()) { - return nullptr; - } - TagLib::File *file = fileRef.file(); - JVMMetadataBuilder builder {env}; + jobject /* this */, + jobject inputStream) { + try { + JVMInputStream stream {env, inputStream}; + TagLib::FileRef fileRef {&stream}; + if (fileRef.isNull()) { + return nullptr; + } + TagLib::File *file = fileRef.file(); + JVMMetadataBuilder builder {env}; - if (auto *mpegFile = dynamic_cast(file)) { - builder.setMimeType("audio/mpeg"); - builder.setId3v2(*mpegFile->ID3v2Tag()); - } else if (auto *mp4File = dynamic_cast(file)) { - builder.setMimeType("audio/mp4"); - builder.setMp4(*mp4File->tag()); - } else if (auto *flacFile = dynamic_cast(file)) { - builder.setMimeType("audio/flac"); - builder.setId3v2(*flacFile->ID3v2Tag()); - builder.setXiph(*flacFile->xiphComment()); - } else if (auto *opusFile = dynamic_cast(file)) { - builder.setMimeType("audio/opus"); - builder.setXiph(*opusFile->tag()); - } else if (auto *vorbisFile = - dynamic_cast(file)) { - builder.setMimeType("audio/vorbis"); - builder.setXiph(*vorbisFile->tag()); - } else if (auto *wavFile = dynamic_cast(file)) { - builder.setMimeType("audio/wav"); - builder.setId3v2(*wavFile->ID3v2Tag()); - } else { - // While taglib supports other formats, ExoPlayer does not. Ignore them. - return nullptr; - } + if (auto *mpegFile = dynamic_cast(file)) { + builder.setMimeType("audio/mpeg"); + builder.setId3v2(*mpegFile->ID3v2Tag()); + } else if (auto *mp4File = dynamic_cast(file)) { + builder.setMimeType("audio/mp4"); + builder.setMp4(*mp4File->tag()); + } else if (auto *flacFile = dynamic_cast(file)) { + builder.setMimeType("audio/flac"); + builder.setId3v2(*flacFile->ID3v2Tag()); + builder.setXiph(*flacFile->xiphComment()); + } else if (auto *opusFile = dynamic_cast(file)) { + builder.setMimeType("audio/opus"); + builder.setXiph(*opusFile->tag()); + } else if (auto *vorbisFile = + dynamic_cast(file)) { + builder.setMimeType("audio/vorbis"); + builder.setXiph(*vorbisFile->tag()); + } else if (auto *wavFile = dynamic_cast(file)) { + builder.setMimeType("audio/wav"); + builder.setId3v2(*wavFile->ID3v2Tag()); + } else { + // While taglib supports other formats, ExoPlayer does not. Ignore them. + return nullptr; + } - builder.setProperties(file->audioProperties()); - builder.setCover(file->tag()->complexProperties("PICTURE")); - return builder.build(); - } catch (std::runtime_error e) { - LOGE("Error opening file: %s", e.what()); - return nullptr; - } + builder.setProperties(file->audioProperties()); + builder.setCover(file->tag()->complexProperties("PICTURE")); + return builder.build(); + } catch (std::runtime_error e) { + LOGE("Error opening file: %s", e.what()); + return nullptr; + } }