diff --git a/app/src/main/rust/src/hash/sha1.rs b/app/src/main/rust/src/hash/sha1.rs
index b8850ed7b..9f590d36a 100644
--- a/app/src/main/rust/src/hash/sha1.rs
+++ b/app/src/main/rust/src/hash/sha1.rs
@@ -8,7 +8,7 @@ use jni_throwing;
use sha1::{Digest, Sha1};
use std::{fs::File, io::copy, os::fd::BorrowedFd};
-pub fn file_sha1(mut file: File, digest: &mut [u8; 40]) -> Result<&str> {
+fn file_sha1(mut file: File, digest: &mut [u8; 40]) -> Result<&str> {
let mut sha = Sha1::new();
copy(&mut file, &mut sha)?;
Ok(encode_str(&sha.finalize(), digest)?)
diff --git a/app/src/main/rust/src/lib.rs b/app/src/main/rust/src/lib.rs
index cfea94bb1..b69d41034 100644
--- a/app/src/main/rust/src/lib.rs
+++ b/app/src/main/rust/src/lib.rs
@@ -15,7 +15,7 @@ extern crate sha1;
extern crate tl;
use android_logger::Config;
-use anyhow::Result;
+use anyhow::{anyhow, Result};
use jni::objects::JByteBuffer;
use jni::sys::{jint, jobject, JavaVM, JNI_VERSION_1_6};
use jni::JNIEnv;
@@ -25,6 +25,7 @@ use std::ffi::c_void;
use std::io::Cursor;
use std::ptr::slice_from_raw_parts_mut;
use std::str::from_utf8_unchecked;
+use tl::ParserOptions;
use tl::{Bytes, Node, NodeHandle, Parser, VDom};
#[macro_export]
@@ -67,15 +68,10 @@ where
handle.get(parser)
}
-fn deref_mut_direct_bytebuffer<'a>(env: &JNIEnv, buffer: JByteBuffer) -> &'a mut [u8] {
- let ptr = env.get_direct_buffer_address(&buffer).unwrap();
- let cap = env.get_direct_buffer_capacity(&buffer).unwrap();
- unsafe { &mut *slice_from_raw_parts_mut(ptr, cap) }
-}
-
-fn throw_msg(env: &mut JNIEnv, msg: &str) -> i32 {
- env.throw_new("java/lang/RuntimeException", msg).ok();
- 0
+fn deref_mut_direct_bytebuffer(env: &JNIEnv, buffer: JByteBuffer) -> Result<&'static mut [u8]> {
+ let ptr = env.get_direct_buffer_address(&buffer)?;
+ let cap = env.get_direct_buffer_capacity(&buffer)?;
+ Ok(unsafe { &mut *slice_from_raw_parts_mut(ptr, cap) })
}
trait ThrowingHasDefault {
@@ -88,6 +84,12 @@ impl ThrowingHasDefault for jobject {
}
}
+impl ThrowingHasDefault for i32 {
+ fn default() -> Self {
+ 0
+ }
+}
+
fn jni_throwing(env: &mut JNIEnv, f: F) -> R
where
F: FnOnce(&mut JNIEnv) -> Result,
@@ -96,7 +98,8 @@ where
match f(env) {
Ok(value) => value,
Err(err) => {
- throw_msg(env, &format!("{err}"));
+ let msg = format!("{err}");
+ env.throw_new("java/lang/RuntimeException", msg).ok();
R::default()
}
}
@@ -104,23 +107,20 @@ where
fn parse_marshal_inplace(env: &mut JNIEnv, str: JByteBuffer, limit: jint, f: F) -> i32
where
- F: Fn(&VDom, &str) -> Result,
+ F: Fn(&VDom, &str) -> Result,
R: Serialize,
{
- let buffer = deref_mut_direct_bytebuffer(env, str);
- let html = unsafe { from_utf8_unchecked(&buffer[..limit as usize]) };
- let value = match tl::parse(html, tl::ParserOptions::default()) {
- Ok(dom) => match f(&dom, html) {
- Err(err) => return throw_msg(env, err),
- Ok(value) => value,
- },
- Err(_) => return throw_msg(env, html),
- };
- let mut cursor = Cursor::new(buffer);
- match serde_cbor::to_writer(&mut cursor, &value) {
- Ok(_) => cursor.position() as i32,
- Err(err) => throw_msg(env, &format!("{}", err)),
- }
+ jni_throwing(env, |env| {
+ let buffer = deref_mut_direct_bytebuffer(env, str)?;
+ let value = {
+ let html = unsafe { from_utf8_unchecked(&buffer[..limit as usize]) };
+ let dom = tl::parse(html, ParserOptions::default()).map_err(|_| anyhow!("{html}"))?;
+ f(&dom, html)?
+ };
+ let mut cursor = Cursor::new(buffer);
+ serde_cbor::to_writer(&mut cursor, &value)?;
+ Ok(cursor.position() as i32)
+ })
}
fn get_node_handle_attr<'a>(
diff --git a/app/src/main/rust/src/parser/fav.rs b/app/src/main/rust/src/parser/fav.rs
index d2586fed8..cfc3298cc 100644
--- a/app/src/main/rust/src/parser/fav.rs
+++ b/app/src/main/rust/src/parser/fav.rs
@@ -1,3 +1,4 @@
+use anyhow::{bail, Result};
use jni::objects::{JByteBuffer, JClass};
use jni::sys::jint;
use jni::JNIEnv;
@@ -17,9 +18,9 @@ struct FavResult {
galleryListResult: GalleryListResult,
}
-fn parse_fav(dom: &VDom, parser: &Parser, html: &str) -> Result {
+fn parse_fav(dom: &VDom, parser: &Parser, html: &str) -> Result {
if html.contains("This page requires you to log on.
") {
- return Err("Not logged in!");
+ bail!("Not logged in!")
}
let vec: Vec<(String, i32)> = dom
.get_elements_by_class_name("fp")
@@ -49,7 +50,7 @@ fn parse_fav(dom: &VDom, parser: &Parser, html: &str) -> Result Option {
#[jni_fn("com.hippo.ehviewer.client.parser.HomeParserKt")]
pub fn parseLimit(mut env: JNIEnv, _class: JClass, input: JByteBuffer, limit: jint) -> jint {
parse_marshal_inplace(&mut env, input, limit, |dom, _| {
- parse_limit(dom, dom.parser()).ok_or("Can't parse Limit")
+ parse_limit(dom, dom.parser()).ok_or(anyhow!("Can't parse Limit"))
})
}
diff --git a/app/src/main/rust/src/parser/list.rs b/app/src/main/rust/src/parser/list.rs
index 7c45ed915..2c45222ce 100644
--- a/app/src/main/rust/src/parser/list.rs
+++ b/app/src/main/rust/src/parser/list.rs
@@ -1,3 +1,4 @@
+use anyhow::{anyhow, bail, Result};
use jni::objects::{JByteBuffer, JClass};
use jni::sys::jint;
use jni::JNIEnv;
@@ -189,16 +190,12 @@ fn parse_gallery_info(node: &Node, parser: &Parser) -> Option {
})
}
-pub fn parse_info_list(
- dom: &VDom,
- parser: &Parser,
- str: &str,
-) -> Result {
+pub fn parse_info_list(dom: &VDom, parser: &Parser, str: &str) -> Result {
if str.contains("You do not have any watched tags") {
- return Err("No watched tags!");
+ bail!("No watched tags!")
}
if str.contains("No hits found
") || str.contains("No unfiltered results found") {
- return Err("No hits found!");
+ bail!("No hits found!")
}
let f = || {
let itg = get_vdom_first_element_by_class_name(dom, "itg")?;
@@ -231,7 +228,7 @@ pub fn parse_info_list(
galleryInfoList: info,
})
};
- f().ok_or("No content")
+ f().ok_or(anyhow!("No content"))
}
#[no_mangle]
diff --git a/app/src/main/rust/src/parser/torrent.rs b/app/src/main/rust/src/parser/torrent.rs
index 514062026..f0822f2b9 100644
--- a/app/src/main/rust/src/parser/torrent.rs
+++ b/app/src/main/rust/src/parser/torrent.rs
@@ -1,3 +1,4 @@
+use anyhow::{anyhow, Result};
use jni::objects::{JByteBuffer, JClass};
use jni::sys::jint;
use jni::JNIEnv;
@@ -18,8 +19,8 @@ struct Torrent {
name: String,
}
-fn parse_torrent_list(dom: &VDom, parser: &Parser) -> Result, &'static str> {
- let list = dom.query_selector("table").ok_or("No Table")?.filter_map(|e| {
+fn parse_torrent_list(dom: &VDom, parser: &Parser) -> Result> {
+ let list = dom.query_selector("table").ok_or(anyhow!("No Table"))?.filter_map(|e| {
let html = e.get(parser)?.inner_html(parser);
if html.contains("Expunged") {
None