musikr: bubblewrap nativeinputstream
Try to avoid exceptions cascading and bringing down the app.
This commit is contained in:
parent
b81ecf44c0
commit
3aae8ea534
2 changed files with 70 additions and 20 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in a new issue