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