diff --git a/app/src/main/rust/Cargo.toml b/app/src/main/rust/Cargo.toml index 20ceaab47..f45f80063 100644 --- a/app/src/main/rust/Cargo.toml +++ b/app/src/main/rust/Cargo.toml @@ -19,7 +19,7 @@ serde_cbor = "0.11" serde = { version = "1.0", features = ["derive"] } [profile.release] +panic = "abort" strip = true -opt-level = "s" lto = true codegen-units = 1 diff --git a/app/src/main/rust/src/lib.rs b/app/src/main/rust/src/lib.rs index 28b7e65cd..7cb6d2c85 100644 --- a/app/src/main/rust/src/lib.rs +++ b/app/src/main/rust/src/lib.rs @@ -18,7 +18,6 @@ use log::LevelFilter; use serde::Serialize; use std::ffi::c_void; use std::io::Cursor; -use std::panic::{catch_unwind, UnwindSafe}; use std::ptr::{slice_from_raw_parts, slice_from_raw_parts_mut}; use std::str::from_utf8_unchecked; use tl::{Bytes, Node, NodeHandle, Parser, VDom}; @@ -34,12 +33,6 @@ macro_rules! regex { const EHGT_PREFIX: &str = "https://ehgt.org/"; const EX_PREFIX: &str = "https://s.exhentai.org/"; -fn check_html(str: &str) { - if !str.contains('<') { - panic!("{}", str) - } -} - fn get_vdom_first_element_by_class_name<'a>(dom: &'a VDom, name: &str) -> Option<&'a Node<'a>> { let handle = dom.get_elements_by_class_name(name).next()?; handle.get(dom.parser()) @@ -71,7 +64,7 @@ where fn parse_marshal_inplace(env: &mut JNIEnv, str: JByteBuffer, limit: jint, mut f: F) -> i32 where - F: FnMut(&VDom, &Parser, &str) -> Option + UnwindSafe, + F: FnMut(&VDom, &Parser, &str) -> Result, R: Serialize, { let ptr = env.get_direct_buffer_address(&str).unwrap(); @@ -79,36 +72,31 @@ where let buff = slice_from_raw_parts(ptr, limit as usize); from_utf8_unchecked(&*buff) }; - let f = move || { - let dom = tl::parse(html, tl::ParserOptions::default()).unwrap(); + let mut f = || { + let dom = tl::parse(html, tl::ParserOptions::default()).map_err(|_| html)?; let parser = dom.parser(); - let result = f(&dom, parser, html); - match result { - // Nothing to marshal - None => 0, - Some(value) => { - let mut cursor = unsafe { - let slice = slice_from_raw_parts_mut(ptr, 0x80000); - Cursor::new(&mut *slice) - }; - serde_cbor::to_writer(&mut cursor, &value).unwrap(); - cursor.position() as i32 - } - } + f(&dom, parser, html) }; - match catch_unwind(f) { - Ok(result) => result, + match f() { + // Nothing to marshal Err(err) => { - let msg = match err.downcast_ref::<&'static str>() { - Some(s) => *s, - None => match err.downcast_ref::() { - Some(s) => &s[..], - None => "Box", - }, - }; - env.throw_new("java/lang/RuntimeException", msg).unwrap(); + env.throw_new("java/lang/RuntimeException", err).ok(); 0 } + Ok(value) => { + let mut cursor = unsafe { + let slice = slice_from_raw_parts_mut(ptr, 0x80000); + Cursor::new(&mut *slice) + }; + match serde_cbor::to_writer(&mut cursor, &value) { + Ok(_) => cursor.position() as i32, + Err(err) => { + env.throw_new("java/lang/RuntimeException", format!("{}", err)) + .ok(); + 0 + } + } + } } } diff --git a/app/src/main/rust/src/parser/fav.rs b/app/src/main/rust/src/parser/fav.rs index 29697e431..b155f5110 100644 --- a/app/src/main/rust/src/parser/fav.rs +++ b/app/src/main/rust/src/parser/fav.rs @@ -17,9 +17,9 @@ struct FavResult { galleryListResult: GalleryListResult, } -fn parse_fav(dom: &VDom, parser: &Parser, html: &str) -> Option { +fn parse_fav(dom: &VDom, parser: &Parser, html: &str) -> Result { if html.contains("This page requires you to log on.

") { - panic!("Not logged in!") + return Err("Not logged in!"); } let vec: Vec<(String, i32)> = dom .get_elements_by_class_name("fp") @@ -43,13 +43,13 @@ fn parse_fav(dom: &VDom, parser: &Parser, html: &str) -> Option { if vec.len() == 10 { let list = parse_info_list(dom, parser, html)?; let cat = vec.iter().cloned().unzip(); - Some(FavResult { + Ok(FavResult { catArray: cat.0, countArray: cat.1, galleryListResult: list, }) } else { - None + Err("Illegal fav cat count!") } } diff --git a/app/src/main/rust/src/parser/home.rs b/app/src/main/rust/src/parser/home.rs index d211c85c3..93f0063bb 100644 --- a/app/src/main/rust/src/parser/home.rs +++ b/app/src/main/rust/src/parser/home.rs @@ -1,12 +1,11 @@ -use get_vdom_first_element_by_class_name; use jni::objects::{JByteBuffer, JClass}; use jni::sys::jint; use jni::JNIEnv; use jni_fn::jni_fn; -use parse_marshal_inplace; use serde::Serialize; use tl::Parser; use tl::VDom; +use {get_vdom_first_element_by_class_name, parse_marshal_inplace}; #[allow(non_snake_case)] #[derive(Serialize)] @@ -35,6 +34,6 @@ fn parse_limit(dom: &VDom, parser: &Parser) -> 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, parser, _| { - parse_limit(dom, parser) + parse_limit(dom, parser).ok_or("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 c7f0da9fe..c73da0cad 100644 --- a/app/src/main/rust/src/parser/list.rs +++ b/app/src/main/rust/src/parser/list.rs @@ -1,4 +1,3 @@ -use check_html; use jni::objects::{JByteBuffer, JClass}; use jni::sys::jint; use jni::JNIEnv; @@ -101,7 +100,7 @@ fn parse_uploader_and_pages(str: &str) -> (Option, bool, i32) { .map(|grp| grp[1].to_string()); let pages = match regex!(r"
(\d+) pages
").captures(str) { None => 0, - Some(grp) => grp[1].parse().unwrap(), + Some(grp) => grp[1].parse().unwrap_or(0), }; (uploader, str.contains("style=\"opacity:0.5\""), pages) } @@ -109,7 +108,7 @@ fn parse_uploader_and_pages(str: &str) -> (Option, bool, i32) { fn parse_thumb_resolution(str: &str) -> (i32, i32) { match regex!(r"height:(\d+)px;width:(\d+)px").captures(str) { None => (0, 0), - Some(grp) => (grp[1].parse().unwrap(), grp[2].parse().unwrap()), + Some(grp) => (grp[1].parse().unwrap_or(0), grp[2].parse().unwrap_or(0)), } } @@ -129,7 +128,7 @@ fn parse_gallery_info(node: &Node, parser: &Parser) -> Option { let (thumb, (thumb_height, thumb_width)) = match tag.query_selector(parser, "[data-src]")?.next() { None => match tag.query_selector(parser, "[src]")?.next() { - None => panic!("No thumb found"), + None => return None, Some(thumb) => ( get_node_handle_attr(&thumb, parser, "src")?, parse_thumb_resolution(get_node_handle_attr(&thumb, parser, "style")?), @@ -190,43 +189,52 @@ fn parse_gallery_info(node: &Node, parser: &Parser) -> Option { }) } -pub fn parse_info_list(dom: &VDom, parser: &Parser, str: &str) -> Option { - check_html(str); +pub fn parse_info_list( + dom: &VDom, + parser: &Parser, + str: &str, +) -> Result { + if !str.contains('<') { + return Err("No content!"); + } if str.contains("

You do not have any watched tags") { - panic!("No watched tags!") + return Err("No watched tags!"); } if str.contains("No hits found

") || str.contains("No unfiltered results found") { - panic!("No hits found!") + return Err("No hits found!"); } - let itg = get_vdom_first_element_by_class_name(dom, "itg")?; - let children = itg.children()?; - let iter = children.top().iter(); - let info: Vec = iter - .filter_map(|x| parse_gallery_info(x.get(parser)?, parser)) - .collect(); - let prev = dom.get_element_by_id("uprev").and_then(|e| { - let str = get_node_handle_attr(&e, parser, "href")?; - Some( - regex!("prev=(\\d+(-\\d+)?)") - .captures(str)? - .index(1) - .to_string(), - ) - }); - let next = dom.get_element_by_id("unext").and_then(|e| { - let str = get_node_handle_attr(&e, parser, "href")?; - Some( - regex!("next=(\\d+(-\\d+)?)") - .captures(str)? - .index(1) - .to_string(), - ) - }); - (!info.is_empty()).then_some(GalleryListResult { - prev, - next, - galleryInfoList: info, - }) + let f = || { + let itg = get_vdom_first_element_by_class_name(dom, "itg")?; + let children = itg.children()?; + let iter = children.top().iter(); + let info: Vec = iter + .filter_map(|x| parse_gallery_info(x.get(parser)?, parser)) + .collect(); + let prev = dom.get_element_by_id("uprev").and_then(|e| { + let str = get_node_handle_attr(&e, parser, "href")?; + Some( + regex!("prev=(\\d+(-\\d+)?)") + .captures(str)? + .index(1) + .to_string(), + ) + }); + let next = dom.get_element_by_id("unext").and_then(|e| { + let str = get_node_handle_attr(&e, parser, "href")?; + Some( + regex!("next=(\\d+(-\\d+)?)") + .captures(str)? + .index(1) + .to_string(), + ) + }); + (!info.is_empty()).then_some(GalleryListResult { + prev, + next, + galleryInfoList: info, + }) + }; + f().ok_or("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 6f1417684..125117720 100644 --- a/app/src/main/rust/src/parser/torrent.rs +++ b/app/src/main/rust/src/parser/torrent.rs @@ -18,13 +18,13 @@ struct Torrent { name: String, } -fn parse_torrent_list(dom: &VDom, parser: &Parser) -> Option> { - let list = dom.query_selector("table")?.filter_map(|e| { +fn parse_torrent_list(dom: &VDom, parser: &Parser) -> Result, &'static str> { + let list = dom.query_selector("table").ok_or("No Table")?.filter_map(|e| { let html = e.get(parser)?.inner_html(parser); if html.contains("Expunged") { None } else { - let grp = regex!(" ([0-9-]+) [0-9:]+[\\s\\S]+ ([0-9.]+ [KMGT]iB)[\\s\\S]+ ([0-9]+)[\\s\\S]+ ([0-9]+)[\\s\\S]+ ([0-9]+)[\\s\\S]+([^<]+)[\\s\\S]+onclick=\"document.location='([^\"]+)'[^<]+>([^<]+)").captures(&html).unwrap(); + let grp = regex!(" ([0-9-]+) [0-9:]+[\\s\\S]+ ([0-9.]+ [KMGT]iB)[\\s\\S]+ ([0-9]+)[\\s\\S]+ ([0-9]+)[\\s\\S]+ ([0-9]+)[\\s\\S]+([^<]+)[\\s\\S]+onclick=\"document.location='([^\"]+)'[^<]+>([^<]+)").captures(&html)?; let name = unescape(&grp[8]).ok()?; Some(Torrent { posted: grp[1].to_string(), @@ -37,7 +37,7 @@ fn parse_torrent_list(dom: &VDom, parser: &Parser) -> Option> { }) } }).collect::>(); - Some(list) + Ok(list) } #[no_mangle]