Skip to main content

cure_java_simplify/
jdk.rs

1//! JDK 类存在性判断——`Class.forName` 假设成功的依据。
2//!
3//! 两级策略:
4//! 1. `--jdk-home` / `CURE_JDK_HOME` 指定 JDK:读 `lib/src.zip` 做字节
5//!    检索(zip 文件名在中央目录中未压缩存储;`.java` 后缀天然锚定,
6//!    无前缀误命中)——精确存在性。
7//! 2. 未指定:java.base 模块包前缀白名单(JLS 强制每个 Java SE 平台
8//!    包含 java.base——这些类在任何合规 JVM 上 forName 必然成功)。
9//!
10//! 语义合同:假设仅覆盖**控制流**(forName 不抛);forName 语句本身
11//! 作为不透明副作用保留在产物中(类初始化可观察)。
12
13use std::sync::OnceLock;
14
15/// java.base 模块的包集合(JLS 强制存在)。
16const JAVA_BASE_PKGS: &[&str] = &[
17    "java.io",
18    "java.lang",
19    "java.lang.annotation",
20    "java.lang.constant",
21    "java.lang.invoke",
22    "java.lang.module",
23    "java.lang.ref",
24    "java.lang.reflect",
25    "java.math",
26    "java.net",
27    "java.net.spi",
28    "java.nio",
29    "java.nio.channels",
30    "java.nio.channels.spi",
31    "java.nio.charset",
32    "java.nio.charset.spi",
33    "java.nio.file",
34    "java.nio.file.attribute",
35    "java.nio.file.spi",
36    "java.security",
37    "java.security.cert",
38    "java.security.interfaces",
39    "java.security.spec",
40    "java.text",
41    "java.text.spi",
42    "java.time",
43    "java.time.chrono",
44    "java.time.format",
45    "java.time.temporal",
46    "java.time.zone",
47    "java.util",
48    "java.util.concurrent",
49    "java.util.concurrent.atomic",
50    "java.util.concurrent.locks",
51    "java.util.function",
52    "java.util.jar",
53    "java.util.logging",
54    "java.util.prefs",
55    "java.util.random",
56    "java.util.regex",
57    "java.util.spi",
58    "java.util.stream",
59    "java.util.zip",
60    "javax.crypto",
61    "javax.crypto.interfaces",
62    "javax.crypto.spec",
63    "javax.net",
64    "javax.net.ssl",
65    "javax.security.auth",
66    "javax.security.auth.callback",
67    "javax.security.auth.login",
68    "javax.security.auth.spi",
69    "javax.security.auth.x500",
70    "javax.security.cert",
71];
72
73fn java_base_prefix(name: &str) -> bool {
74    // 嵌套类(java.util.Map$Entry)以外部类判断
75    let base = name.split('$').next().unwrap_or(name);
76    let base = base.trim();
77    JAVA_BASE_PKGS
78        .iter()
79        .any(|p| base == *p || base.starts_with(p) && base.as_bytes().get(p.len()) == Some(&b'.'))
80}
81
82/// src.zip 全量字节(~54MB,仅在 --jdk-home 时加载一次)。
83static JDK_SRC: OnceLock<Option<std::sync::Arc<Vec<u8>>>> = OnceLock::new();
84
85/// 主线程(CLI)在并行 worker 启动前调用。也支持 CURE_JDK_HOME 环境变量。
86pub fn set_jdk_home(path: &std::path::Path) {
87    let zip = path.join("lib").join("src.zip");
88    if let Ok(data) = std::fs::read(&zip) {
89        let _ = JDK_SRC.set(Some(std::sync::Arc::new(data)));
90    }
91}
92
93fn jdk_src() -> Option<std::sync::Arc<Vec<u8>>> {
94    if let Some(v) = JDK_SRC.get() {
95        return v.clone();
96    }
97    if let Ok(p) = std::env::var("CURE_JDK_HOME") {
98        set_jdk_home(std::path::Path::new(&p));
99    }
100    JDK_SRC.get().cloned().flatten()
101}
102
103/// `Class.forName(name)` 是否可假设成功。
104/// 未知/可判定不存在 → false(保守 abort)。
105pub fn class_loads(name: &str) -> bool {
106    if let Some(src) = jdk_src() {
107        // 精确存在性:"java/security/MessageDigest.java"
108        // (.java 后缀防止前缀误命中:Col.java 不是 Collection.java 的子串)
109        let slash: String = name.replace('.', "/");
110        let needle = format!("{}.java", slash);
111        return find_sub(&src, needle.as_bytes());
112    }
113    java_base_prefix(name)
114}
115
116fn find_sub(hay: &[u8], needle: &[u8]) -> bool {
117    if needle.is_empty() || hay.len() < needle.len() {
118        return false;
119    }
120    let n = needle.len();
121    let first = needle[0];
122    let mut i = 0usize;
123    let last = hay.len() - n;
124    while i <= last {
125        if hay[i] == first && &hay[i..i + n] == needle {
126            return true;
127        }
128        i += 1;
129    }
130    false
131}