use std::sync::OnceLock;
const JAVA_BASE_PKGS: &[&str] = &[
"java.io",
"java.lang",
"java.lang.annotation",
"java.lang.constant",
"java.lang.invoke",
"java.lang.module",
"java.lang.ref",
"java.lang.reflect",
"java.math",
"java.net",
"java.net.spi",
"java.nio",
"java.nio.channels",
"java.nio.channels.spi",
"java.nio.charset",
"java.nio.charset.spi",
"java.nio.file",
"java.nio.file.attribute",
"java.nio.file.spi",
"java.security",
"java.security.cert",
"java.security.interfaces",
"java.security.spec",
"java.text",
"java.text.spi",
"java.time",
"java.time.chrono",
"java.time.format",
"java.time.temporal",
"java.time.zone",
"java.util",
"java.util.concurrent",
"java.util.concurrent.atomic",
"java.util.concurrent.locks",
"java.util.function",
"java.util.jar",
"java.util.logging",
"java.util.prefs",
"java.util.random",
"java.util.regex",
"java.util.spi",
"java.util.stream",
"java.util.zip",
"javax.crypto",
"javax.crypto.interfaces",
"javax.crypto.spec",
"javax.net",
"javax.net.ssl",
"javax.security.auth",
"javax.security.auth.callback",
"javax.security.auth.login",
"javax.security.auth.spi",
"javax.security.auth.x500",
"javax.security.cert",
];
fn java_base_prefix(name: &str) -> bool {
let base = name.split('$').next().unwrap_or(name);
let base = base.trim();
JAVA_BASE_PKGS
.iter()
.any(|p| base == *p || base.starts_with(p) && base.as_bytes().get(p.len()) == Some(&b'.'))
}
static JDK_SRC: OnceLock<Option<std::sync::Arc<Vec<u8>>>> = OnceLock::new();
pub fn set_jdk_home(path: &std::path::Path) {
let zip = path.join("lib").join("src.zip");
if let Ok(data) = std::fs::read(&zip) {
let _ = JDK_SRC.set(Some(std::sync::Arc::new(data)));
}
}
fn jdk_src() -> Option<std::sync::Arc<Vec<u8>>> {
if let Some(v) = JDK_SRC.get() {
return v.clone();
}
if let Ok(p) = std::env::var("CURE_JDK_HOME") {
set_jdk_home(std::path::Path::new(&p));
}
JDK_SRC.get().cloned().flatten()
}
pub fn class_loads(name: &str) -> bool {
if let Some(src) = jdk_src() {
let slash: String = name.replace('.', "/");
let needle = format!("{}.java", slash);
return find_sub(&src, needle.as_bytes());
}
java_base_prefix(name)
}
fn find_sub(hay: &[u8], needle: &[u8]) -> bool {
if needle.is_empty() || hay.len() < needle.len() {
return false;
}
let n = needle.len();
let first = needle[0];
let mut i = 0usize;
let last = hay.len() - n;
while i <= last {
if hay[i] == first && &hay[i..i + n] == needle {
return true;
}
i += 1;
}
false
}