musikr: bubblewrap jvminputstream

Should help me ID some error.
This commit is contained in:
Alexander Capehart 2025-01-14 08:53:03 -07:00
parent 71aa887438
commit b6d80189ca
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
4 changed files with 79 additions and 28 deletions

View file

@ -48,6 +48,7 @@ add_library(${CMAKE_PROJECT_NAME} SHARED
JVMInputStream.cpp JVMInputStream.cpp
JVMTagMap.cpp JVMTagMap.cpp
JVMMetadataBuilder.cpp JVMMetadataBuilder.cpp
util.cpp
) )
target_link_options(${CMAKE_PROJECT_NAME} target_link_options(${CMAKE_PROJECT_NAME}
# @Tolriq found that these flags can reduce the size of the linked # @Tolriq found that these flags can reduce the size of the linked

View file

@ -17,32 +17,42 @@
*/ */
#include "JVMInputStream.h" #include "JVMInputStream.h"
#include "util.h"
#include <cmath> #include <cmath>
// TODO: Handle stream exceptions // TODO: Handle stream exceptions
JVMInputStream::JVMInputStream(JNIEnv *env, jobject inputStream) : env(env), inputStream( JVMInputStream::JVMInputStream(JNIEnv *env, jobject inputStream) : env(env), inputStream(
inputStream) { inputStream) {
if (!env->IsInstanceOf(inputStream, TRY(auto isNativeInputStream = env->IsInstanceOf(inputStream,
env->FindClass("org/oxycblt/musikr/metadata/NativeInputStream"))) { env->FindClass("org/oxycblt/musikr/metadata/NativeInputStream")))
if (!isNativeInputStream) {
throw std::runtime_error("oStream is not an instance of TagLibOStream"); throw std::runtime_error("oStream is not an instance of TagLibOStream");
} }
jclass inputStreamClass = env->FindClass( TRY(jclass inputStreamClass = env->FindClass(
"org/oxycblt/musikr/metadata/NativeInputStream"); "org/oxycblt/musikr/metadata/NativeInputStream"));
inputStreamReadBlockMethod = env->GetMethodID(inputStreamClass, "readBlock", TRY(
"(J)[B"); inputStreamReadBlockMethod = env->GetMethodID(inputStreamClass,
inputStreamIsOpenMethod = env->GetMethodID(inputStreamClass, "isOpen", "readBlock", "(J)[B"));
"()Z"); TRY(
inputStreamSeekFromBeginningMethod = env->GetMethodID(inputStreamClass, inputStreamIsOpenMethod = env->GetMethodID(inputStreamClass,
"seekFromBeginning", "(J)V"); "isOpen", "()Z"));
inputStreamSeekFromCurrentMethod = env->GetMethodID(inputStreamClass, TRY(
"seekFromCurrent", "(J)V"); inputStreamSeekFromBeginningMethod = env->GetMethodID(
inputStreamClass, "seekFromBeginning", "(J)V"));
TRY(
inputStreamSeekFromCurrentMethod = env->GetMethodID(
inputStreamClass, "seekFromCurrent", "(J)V"));
TRY(
inputStreamSeekFromEndMethod = env->GetMethodID(inputStreamClass, inputStreamSeekFromEndMethod = env->GetMethodID(inputStreamClass,
"seekFromEnd", "(J)V"); "seekFromEnd", "(J)V"));
inputStreamTellMethod = env->GetMethodID(inputStreamClass, "tell", "()J"); TRY(
inputStreamLengthMethod = env->GetMethodID(inputStreamClass, "length", inputStreamTellMethod = env->GetMethodID(inputStreamClass, "tell",
"()J"); "()J"));
env->DeleteLocalRef(inputStreamClass); TRY(
inputStreamLengthMethod = env->GetMethodID(inputStreamClass,
"length", "()J"));
TRY(env->DeleteLocalRef(inputStreamClass));
} }
JVMInputStream::~JVMInputStream() { JVMInputStream::~JVMInputStream() {
@ -56,13 +66,15 @@ TagLib::FileName JVMInputStream::name() const {
} }
TagLib::ByteVector JVMInputStream::readBlock(size_t length) { TagLib::ByteVector JVMInputStream::readBlock(size_t length) {
auto data = (jbyteArray) env->CallObjectMethod(inputStream, TRY(auto data = (jbyteArray) env->CallObjectMethod(inputStream,
inputStreamReadBlockMethod, length); inputStreamReadBlockMethod, length));
jsize dataLength = env->GetArrayLength(data); // Check for an exception
auto dataBytes = env->GetByteArrayElements(data, nullptr); // If we don't do this, data == nullptr and the remaining calls crash.
TRY(jsize dataLength = env->GetArrayLength(data));
TRY(auto dataBytes = env->GetByteArrayElements(data, nullptr));
TagLib::ByteVector byteVector(reinterpret_cast<const char*>(dataBytes), TagLib::ByteVector byteVector(reinterpret_cast<const char*>(dataBytes),
dataLength); dataLength);
env->ReleaseByteArrayElements(data, dataBytes, JNI_ABORT); TRY(env->ReleaseByteArrayElements(data, dataBytes, JNI_ABORT));
return byteVector; return byteVector;
} }
@ -84,15 +96,17 @@ bool JVMInputStream::readOnly() const {
} }
bool JVMInputStream::isOpen() const { bool JVMInputStream::isOpen() const {
return env->CallBooleanMethod(inputStream, inputStreamIsOpenMethod); TRY(auto result = env->CallBooleanMethod(inputStream, inputStreamIsOpenMethod));
return result;
} }
void JVMInputStream::seek(TagLib::offset_t offset, Position p) { void JVMInputStream::seek(TagLib::offset_t offset, Position p) {
auto joffset = static_cast<jlong>(std::llround(offset)); auto joffset = static_cast<jlong>(std::llround(offset));
switch (p) { switch (p) {
case Beginning: case Beginning:
env->CallVoidMethod(inputStream, inputStreamSeekFromBeginningMethod, TRY(
joffset); env->CallVoidMethod(inputStream,
inputStreamSeekFromBeginningMethod, joffset));
break; break;
case Current: case Current:
env->CallVoidMethod(inputStream, inputStreamSeekFromCurrentMethod, env->CallVoidMethod(inputStream, inputStreamSeekFromCurrentMethod,
@ -109,12 +123,12 @@ void JVMInputStream::clear() {
} }
TagLib::offset_t JVMInputStream::tell() const { TagLib::offset_t JVMInputStream::tell() const {
jlong jposition = env->CallLongMethod(inputStream, inputStreamTellMethod); TRY(jlong jposition = env->CallLongMethod(inputStream, inputStreamTellMethod));
return static_cast<TagLib::offset_t>(jposition); return static_cast<TagLib::offset_t>(jposition);
} }
TagLib::offset_t JVMInputStream::length() { TagLib::offset_t JVMInputStream::length() {
jlong jlength = env->CallLongMethod(inputStream, inputStreamLengthMethod); TRY(jlong jlength = env->CallLongMethod(inputStream, inputStreamLengthMethod));
return static_cast<TagLib::offset_t>(jlength); return static_cast<TagLib::offset_t>(jlength);
} }

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2025 Auxio Project
* util.cpp 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 <https://www.gnu.org/licenses/>.
*/
#include <stdexcept>
#include "util.h"
void jni_check(JNIEnv *env) {
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
throw std::runtime_error(
"An exception occurred in a JNI call, see logcat");
}
}

View file

@ -28,4 +28,10 @@
#define LOGD(...) \ #define LOGD(...) \
((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
void jni_check(JNIEnv *env);
#define TRY(block) \
block; \
jni_check(env);
#endif //AUXIO_UTIL_H #endif //AUXIO_UTIL_H