Don't unwind (#574)
* Don't unwind * Fixes * Abort in panic * Refine --------- Co-authored-by: GG Bond <whatever@tagkong.com>
This commit is contained in:
1 parent
ba53d01fa1
commit
3ea6c82a6d
6 files changed
+77
-82
No files matched your search
@@ -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
|
||||
@@ -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<F, R>(env: &mut JNIEnv, str: JByteBuffer, limit: jint, mut f: F) -> i32
|
||||
where
|
||||
F: FnMut(&VDom, &Parser, &str) -> Option<R> + UnwindSafe,
|
||||
F: FnMut(&VDom, &Parser, &str) -> Result<R, &'static str>,
|
||||
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::<String>() {
|
||||
Some(s) => &s[..],
|
||||
None => "Box<dyn Any>",
|
||||
},
|
||||
};
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@ struct FavResult {
|
||||
galleryListResult: GalleryListResult,
|
||||
}
|
||||
|
||||
fn parse_fav(dom: &VDom, parser: &Parser, html: &str) -> Option<FavResult> {
|
||||
fn parse_fav(dom: &VDom, parser: &Parser, html: &str) -> Result<FavResult, &'static str> {
|
||||
if html.contains("This page requires you to log on.</p>") {
|
||||
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<FavResult> {
|
||||
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!")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Limits> {
|
||||
#[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")
|
||||
})
|
||||
}
|
||||
@@ -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<String>, bool, i32) {
|
||||
.map(|grp| grp[1].to_string());
|
||||
let pages = match regex!(r"<div>(\d+) pages</div>").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<String>, 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<BaseGalleryInfo> {
|
||||
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<BaseGalleryInfo> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_info_list(dom: &VDom, parser: &Parser, str: &str) -> Option<GalleryListResult> {
|
||||
check_html(str);
|
||||
pub fn parse_info_list(
|
||||
dom: &VDom,
|
||||
parser: &Parser,
|
||||
str: &str,
|
||||
) -> Result<GalleryListResult, &'static str> {
|
||||
if !str.contains('<') {
|
||||
return Err("No content!");
|
||||
}
|
||||
if str.contains("<p>You do not have any watched tags") {
|
||||
panic!("No watched tags!")
|
||||
return Err("No watched tags!");
|
||||
}
|
||||
if str.contains("No hits found</p>") || 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<BaseGalleryInfo> = 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<BaseGalleryInfo> = 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]
|
||||
|
||||
@@ -18,13 +18,13 @@ struct Torrent {
|
||||
name: String,
|
||||
}
|
||||
|
||||
fn parse_torrent_list(dom: &VDom, parser: &Parser) -> Option<Vec<Torrent>> {
|
||||
let list = dom.query_selector("table")?.filter_map(|e| {
|
||||
fn parse_torrent_list(dom: &VDom, parser: &Parser) -> Result<Vec<Torrent>, &'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!("</span> ([0-9-]+) [0-9:]+</td>[\\s\\S]+</span> ([0-9.]+ [KMGT]iB)</td>[\\s\\S]+</span> ([0-9]+)</td>[\\s\\S]+</span> ([0-9]+)</td>[\\s\\S]+</span> ([0-9]+)</td>[\\s\\S]+</span>([^<]+)</td>[\\s\\S]+onclick=\"document.location='([^\"]+)'[^<]+>([^<]+)</a>").captures(&html).unwrap();
|
||||
let grp = regex!("</span> ([0-9-]+) [0-9:]+</td>[\\s\\S]+</span> ([0-9.]+ [KMGT]iB)</td>[\\s\\S]+</span> ([0-9]+)</td>[\\s\\S]+</span> ([0-9]+)</td>[\\s\\S]+</span> ([0-9]+)</td>[\\s\\S]+</span>([^<]+)</td>[\\s\\S]+onclick=\"document.location='([^\"]+)'[^<]+>([^<]+)</a>").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<Vec<Torrent>> {
|
||||
})
|
||||
}
|
||||
}).collect::<Vec<Torrent>>();
|
||||
Some(list)
|
||||
Ok(list)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
Reference in new issue
Block a user