musikr: bubblewrap nativeinputstream

Try to avoid exceptions cascading and bringing down the app.
This commit is contained in:
Alexander Capehart 2025-01-18 09:58:05 -07:00
parent b81ecf44c0
commit 3aae8ea534
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
2 changed files with 70 additions and 20 deletions

View file

@ -34,11 +34,11 @@ JVMInputStream::JVMInputStream(JNIEnv *env, jobject inputStream) : env(env), inp
inputStreamIsOpenMethod = env->GetMethodID(inputStreamClass, "isOpen", inputStreamIsOpenMethod = env->GetMethodID(inputStreamClass, "isOpen",
"()Z"); "()Z");
inputStreamSeekFromBeginningMethod = env->GetMethodID(inputStreamClass, inputStreamSeekFromBeginningMethod = env->GetMethodID(inputStreamClass,
"seekFromBeginning", "(J)V"); "seekFromBeginning", "(J)Z");
inputStreamSeekFromCurrentMethod = env->GetMethodID(inputStreamClass, inputStreamSeekFromCurrentMethod = env->GetMethodID(inputStreamClass,
"seekFromCurrent", "(J)V"); "seekFromCurrent", "(J)Z");
inputStreamSeekFromEndMethod = env->GetMethodID(inputStreamClass, inputStreamSeekFromEndMethod = env->GetMethodID(inputStreamClass,
"seekFromEnd", "(J)V"); "seekFromEnd", "(J)Z");
inputStreamTellMethod = env->GetMethodID(inputStreamClass, "tell", "()J"); inputStreamTellMethod = env->GetMethodID(inputStreamClass, "tell", "()J");
inputStreamLengthMethod = env->GetMethodID(inputStreamClass, "length", inputStreamLengthMethod = env->GetMethodID(inputStreamClass, "length",
"()J"); "()J");
@ -58,6 +58,9 @@ 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, auto data = (jbyteArray) env->CallObjectMethod(inputStream,
inputStreamReadBlockMethod, length); inputStreamReadBlockMethod, length);
if (data == nullptr) {
throw std::runtime_error("Failed to read block, see logs");
}
jsize dataLength = env->GetArrayLength(data); jsize dataLength = env->GetArrayLength(data);
auto dataBytes = env->GetByteArrayElements(data, nullptr); auto dataBytes = env->GetByteArrayElements(data, nullptr);
TagLib::ByteVector byteVector(reinterpret_cast<const char*>(dataBytes), TagLib::ByteVector byteVector(reinterpret_cast<const char*>(dataBytes),
@ -89,19 +92,24 @@ bool JVMInputStream::isOpen() const {
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));
jboolean result;
switch (p) { switch (p) {
case Beginning: case Beginning:
env->CallVoidMethod(inputStream, inputStreamSeekFromBeginningMethod, result = env->CallBooleanMethod(inputStream,
joffset); inputStreamSeekFromBeginningMethod, joffset);
break; break;
case Current: case Current:
env->CallVoidMethod(inputStream, inputStreamSeekFromCurrentMethod, result = env->CallBooleanMethod(inputStream,
joffset); inputStreamSeekFromCurrentMethod, joffset);
break; break;
case End: case End:
env->CallVoidMethod(inputStream, inputStreamSeekFromEndMethod, joffset); result = env->CallBooleanMethod(inputStream,
inputStreamSeekFromEndMethod, joffset);
break; break;
} }
if (!result) {
throw std::runtime_error("Failed to seek, see logs");
}
} }
void JVMInputStream::clear() { void JVMInputStream::clear() {
@ -110,11 +118,17 @@ void JVMInputStream::clear() {
TagLib::offset_t JVMInputStream::tell() const { TagLib::offset_t JVMInputStream::tell() const {
jlong jposition = env->CallLongMethod(inputStream, inputStreamTellMethod); jlong jposition = env->CallLongMethod(inputStream, inputStreamTellMethod);
if (jposition == INT64_MIN) {
throw std::runtime_error("Failed to get position, see logs");
}
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); jlong jlength = env->CallLongMethod(inputStream, inputStreamLengthMethod);
if (jlength == INT64_MIN) {
throw std::runtime_error("Failed to get length, see logs");
}
return static_cast<TagLib::offset_t>(jlength); return static_cast<TagLib::offset_t>(jlength);
} }

View file

@ -18,37 +18,73 @@
package org.oxycblt.musikr.metadata package org.oxycblt.musikr.metadata
import android.util.Log
import java.io.FileInputStream import java.io.FileInputStream
import java.nio.ByteBuffer import java.nio.ByteBuffer
internal class NativeInputStream(fis: FileInputStream) { internal class NativeInputStream(fis: FileInputStream) {
private val channel = fis.channel private val channel = fis.channel
fun readBlock(length: Long): ByteArray { fun readBlock(length: Long): ByteArray? {
val buffer = ByteBuffer.allocate(length.toInt()) try {
channel.read(buffer) val buffer = ByteBuffer.allocate(length.toInt())
return buffer.array() channel.read(buffer)
return buffer.array()
} catch (e: Exception) {
Log.d("NativeInputStream", "Error reading block", e)
return null
}
} }
fun isOpen(): Boolean { fun isOpen(): Boolean {
return channel.isOpen return channel.isOpen
} }
fun seekFromBeginning(offset: Long) { fun seekFromBeginning(offset: Long): Boolean {
channel.position(offset) try {
channel.position(offset)
return true
} catch (e: Exception) {
Log.d("NativeInputStream", "Error seeking from beginning", e)
return false
}
} }
fun seekFromCurrent(offset: Long) { fun seekFromCurrent(offset: Long): Boolean {
channel.position(channel.position() + offset) try {
channel.position(channel.position() + offset)
return true
} catch (e: Exception) {
Log.d("NativeInputStream", "Error seeking from current", e)
return false
}
} }
fun seekFromEnd(offset: Long) { fun seekFromEnd(offset: Long): Boolean {
channel.position(channel.size() + offset) try {
channel.position(channel.size() + offset)
return true
} catch (e: Exception) {
Log.d("NativeInputStream", "Error seeking from end", e)
return false
}
} }
fun tell() = channel.position() fun tell() =
try {
channel.position()
} catch (e: Exception) {
Log.d("NativeInputStream", "Error getting position", e)
Long.MIN_VALUE
}
fun length() = channel.size() fun length() =
try {
channel.size()
} catch (e: Exception) {
Log.d("NativeInputStream", "Error getting length", e)
Long.MIN_VALUE
}
fun close() { fun close() {
channel.close() channel.close()