Remove pelite dependency

The advantages of using the built-in implementation instead of pelite are:

- It's much faster on average: for Starfield.exe (~ 100 MB) it is 2.8x
  faster and 4% slower reading file and product versions respectively,
  and for sfse_1_15_222.dll it is 3.35x faster and < 1% slower
  respectively.
- It reduces the transitive dependency count by 8
- It uses ~ 700 lines of first-party code that only depends on the
  standard library, instead of 240715 lines of unaudited third-party code
- pelite hasn't had a release in 3 years, and my PR for replacing winapi
  hasn't had any response in the month and a half it's been open, so the
  built-in implementation is probably less of a maintenance risk.
This commit is contained in:
Oliver Hamlet
2025-12-03 18:39:27 +00:00
parent daf229c1e9
commit 5aa61abc10
4 changed files with 2 additions and 190 deletions
Generated
-63
View File
@@ -179,21 +179,6 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
[[package]]
name = "dataview"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50eb3a329e19d78c3a3dfa4ec5a51ecb84fa3a20c06edad04be25356018218f9"
dependencies = [
"derive_pod",
]
[[package]]
name = "derive_pod"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2ea6706d74fca54e15f1d40b5cf7fe7f764aaec61352a9fcec58fe27e042fc8"
[[package]] [[package]]
name = "either" name = "either"
version = "1.15.0" version = "1.15.0"
@@ -310,7 +295,6 @@ dependencies = [
"criterion", "criterion",
"esplugin", "esplugin",
"nom", "nom",
"pelite",
"regex", "regex",
"tempfile", "tempfile",
"unicase", "unicase",
@@ -330,12 +314,6 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "no-std-compat"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
[[package]] [[package]]
name = "nom" name = "nom"
version = "8.0.0" version = "8.0.0"
@@ -366,25 +344,6 @@ version = "11.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]]
name = "pelite"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88dccf4bd32294364aeb7bd55d749604450e9db54605887551f21baea7617685"
dependencies = [
"dataview",
"libc",
"no-std-compat",
"pelite-macros",
"winapi",
]
[[package]]
name = "pelite-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a7cf3f8ecebb0f4895f4892a8be0a0dc81b498f9d56735cb769dc31bf00815b"
[[package]] [[package]]
name = "plotters" name = "plotters"
version = "0.3.7" version = "0.3.7"
@@ -685,22 +644,6 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]] [[package]]
name = "winapi-util" name = "winapi-util"
version = "0.1.11" version = "0.1.11"
@@ -710,12 +653,6 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "windows-link" name = "windows-link"
version = "0.2.0" version = "0.2.0"
-1
View File
@@ -11,7 +11,6 @@ edition.workspace = true
crc32fast = "1" crc32fast = "1"
esplugin = "6" esplugin = "6"
nom = "8" nom = "8"
pelite = ">= 0.9.0, < 0.11"
regex = ">= 0.2.7, < 2" regex = ">= 0.2.7, < 2"
unicase = "2" unicase = "2"
+2 -94
View File
@@ -3,9 +3,6 @@ mod pe;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::path::Path; use std::path::Path;
use pelite::resources::version_info::VersionInfo;
use pelite::resources::{FindError, Resources};
use crate::error::Error; use crate::error::Error;
use pe::{read_file_version, read_pe_version, read_product_version}; use pe::{read_file_version, read_pe_version, read_product_version};
@@ -113,105 +110,16 @@ pub(super) struct Version {
impl Version { impl Version {
pub(super) fn read_file_version(file_path: &Path) -> Result<Option<Self>, Error> { pub(super) fn read_file_version(file_path: &Path) -> Result<Option<Self>, Error> {
let version = read_pe_version(file_path, read_file_version)?; read_pe_version(file_path, read_file_version)
let pelite_version = Self::read_version(file_path, |v| {
v.fixed().map(|f| {
format!(
"{}.{}.{}.{}",
f.dwFileVersion.Major,
f.dwFileVersion.Minor,
f.dwFileVersion.Patch,
f.dwFileVersion.Build
)
})
});
compare_versions(file_path, version, pelite_version)
} }
pub(super) fn read_product_version(file_path: &Path) -> Result<Option<Self>, Error> { pub(super) fn read_product_version(file_path: &Path) -> Result<Option<Self>, Error> {
let version = read_pe_version(file_path, read_product_version)?; read_pe_version(file_path, read_product_version)
let pelite_version = Self::read_version(file_path, |v| {
v.translation()
.first()
.and_then(|language| v.value(*language, "ProductVersion"))
});
compare_versions(file_path, version, pelite_version)
} }
pub(super) fn is_readable(file_path: &Path) -> bool { pub(super) fn is_readable(file_path: &Path) -> bool {
read_pe_version(file_path, |_| Ok(None)).is_ok() read_pe_version(file_path, |_| Ok(None)).is_ok()
} }
fn read_version<F: Fn(VersionInfo) -> Option<String>>(
file_path: &Path,
formatter: F,
) -> Result<Option<Self>, Error> {
#[cfg(any(windows, unix))]
let result = {
let file_map = pelite::FileMap::open(file_path)
.map_err(|e| Error::IoError(file_path.to_path_buf(), e))?;
get_pe_version_info(file_map.as_ref()).map(formatter)
};
#[cfg(not(any(windows, unix)))]
let result = {
let bytes =
std::fs::read(file_path).map_err(|e| Error::IoError(file_path.to_path_buf(), e))?;
get_pe_version_info(&bytes).map(formatter)
};
match result {
Ok(s) => Ok(s.map(Version::from)),
Err(FindError::NotFound) => Ok(None),
Err(e) => Err(Error::PeParsingError(file_path.to_path_buf(), Box::new(e))),
}
}
}
fn compare_versions(
file_path: &Path,
version: Option<Version>,
pelite_version: Result<Option<Version>, Error>,
) -> Result<Option<Version>, Error> {
match pelite_version {
Ok(pv) if pv == version => Ok(version),
Ok(pv) => Err(Error::PeParsingError(
file_path.to_path_buf(),
format!("Versions parsed by object and pelite don't match: {version:?} != {pv:?}")
.into(),
)),
Err(e) => Err(Error::PeParsingError(
file_path.to_path_buf(),
format!("pelite errored when parsing version but built-in parser did not: {e}").into(),
)),
}
}
fn get_pe_version_info(bytes: &[u8]) -> Result<VersionInfo<'_>, FindError> {
get_pe_resources(bytes)?.version_info()
}
fn get_pe_resources(bytes: &[u8]) -> Result<Resources<'_>, pelite::Error> {
use pelite::pe64;
match pe64::PeFile::from_bytes(bytes) {
Ok(file) => {
use pelite::pe64::Pe;
file.resources()
}
Err(pelite::Error::PeMagic) => {
use pelite::pe32::{Pe, PeFile};
PeFile::from_bytes(bytes)?.resources()
}
Err(e) => Err(e),
}
} }
fn is_separator(c: char) -> bool { fn is_separator(c: char) -> bool {
-32
View File
@@ -38,14 +38,6 @@ criteria = "safe-to-run"
version = "0.6.0" version = "0.6.0"
criteria = "safe-to-run" criteria = "safe-to-run"
[[exemptions.dataview]]
version = "1.0.1"
criteria = "safe-to-deploy"
[[exemptions.derive_pod]]
version = "0.1.2"
criteria = "safe-to-deploy"
[[exemptions.errno]] [[exemptions.errno]]
version = "0.3.14" version = "0.3.14"
criteria = "safe-to-run" criteria = "safe-to-run"
@@ -68,22 +60,10 @@ notes = "At time of review this was only built if targeting WASM, which is not a
version = "2.7.4" version = "2.7.4"
criteria = "safe-to-deploy" criteria = "safe-to-deploy"
[[exemptions.no-std-compat]]
version = "0.4.1"
criteria = "safe-to-deploy"
[[exemptions.nom]] [[exemptions.nom]]
version = "8.0.0" version = "8.0.0"
criteria = "safe-to-deploy" criteria = "safe-to-deploy"
[[exemptions.pelite]]
version = "0.10.0"
criteria = "safe-to-deploy"
[[exemptions.pelite-macros]]
version = "0.1.1"
criteria = "safe-to-deploy"
[[exemptions.plotters]] [[exemptions.plotters]]
version = "0.3.7" version = "0.3.7"
criteria = "safe-to-run" criteria = "safe-to-run"
@@ -157,15 +137,3 @@ version = "0.3.77"
criteria = "safe-to-run" criteria = "safe-to-run"
suggest = false suggest = false
notes = "At time of review this was only built if targeting WASM, which is not an intended target." notes = "At time of review this was only built if targeting WASM, which is not an intended target."
[[exemptions.winapi]]
version = "0.3.9"
criteria = "safe-to-deploy"
[[exemptions.winapi-i686-pc-windows-gnu]]
version = "0.4.0"
criteria = "safe-to-deploy"
[[exemptions.winapi-x86_64-pc-windows-gnu]]
version = "0.4.0"
criteria = "safe-to-deploy"