mirror of
https://github.com/loot/loot-condition-interpreter.git
synced 2026-07-27 14:16:09 -07:00
Support reading file version from Windows executables
This commit is contained in:
@@ -3,3 +3,4 @@
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
/testing-plugins
|
||||
/loot_api*
|
||||
|
||||
@@ -6,6 +6,7 @@ authors = ["Oliver Hamlet <oliver.hamlet@gmail.com>"]
|
||||
[dependencies]
|
||||
crc = "1.0.0"
|
||||
nom = "4.0.0"
|
||||
pelite = "0.7.0"
|
||||
regex = "1.0.5"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -21,4 +21,5 @@ Currently only condition parsing is complete. Evaluation is partially done, the
|
||||
rest hasn't yet been started.
|
||||
|
||||
The tests need the [testing-plugins](https://github.com/WrinklyNinja/testing-plugins)
|
||||
directory to be present in the repo root.
|
||||
and the [LOOT API v0.13.8](https://github.com/loot/loot-api/releases/tag/0.13.8)
|
||||
Windows archives to be extracted and present in the repo root.
|
||||
|
||||
+8
-2
@@ -1,6 +1,7 @@
|
||||
extern crate crc;
|
||||
#[macro_use]
|
||||
extern crate nom;
|
||||
extern crate pelite;
|
||||
extern crate regex;
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -24,8 +25,7 @@ use function::Function;
|
||||
pub enum Error {
|
||||
ParsingIncomplete,
|
||||
ParsingError,
|
||||
InvalidPath(PathBuf),
|
||||
InvalidRegex(String),
|
||||
PeParsingError,
|
||||
IoError(io::Error),
|
||||
}
|
||||
|
||||
@@ -44,6 +44,12 @@ impl From<io::Error> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pelite::resources::FindError> for Error {
|
||||
fn from(_: pelite::resources::FindError) -> Self {
|
||||
Error::PeParsingError
|
||||
}
|
||||
}
|
||||
|
||||
pub enum GameType {
|
||||
Tes4,
|
||||
Tes5,
|
||||
|
||||
+75
-3
@@ -1,6 +1,10 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::path::Path;
|
||||
|
||||
use pelite::resources::version_info::VersionInfo;
|
||||
use pelite::resources::FindError;
|
||||
use pelite::FileMap;
|
||||
|
||||
use Error;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
@@ -25,8 +29,40 @@ pub struct Version {
|
||||
|
||||
impl Version {
|
||||
pub fn read_file_version(file_path: &Path) -> Result<Self, Error> {
|
||||
// TODO: Actually read the file's File Version field.
|
||||
Ok(Version::from(format!("{}", file_path.display()).as_str()))
|
||||
let file_map = FileMap::open(file_path)?;
|
||||
let version_info = get_pe_version_info(file_map.as_ref())?;
|
||||
|
||||
if let Some(fixed_file_info) = version_info.fixed() {
|
||||
let version = format!(
|
||||
"{}.{}.{}.{}",
|
||||
fixed_file_info.dwFileVersion.Major,
|
||||
fixed_file_info.dwFileVersion.Minor,
|
||||
fixed_file_info.dwFileVersion.Patch,
|
||||
fixed_file_info.dwFileVersion.Build
|
||||
);
|
||||
|
||||
Ok(Version::from(version.as_str()))
|
||||
} else {
|
||||
Ok(Version::from(""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_pe_version_info(bytes: &[u8]) -> Result<VersionInfo, FindError> {
|
||||
use pelite;
|
||||
use pelite::pe64;
|
||||
match pe64::PeFile::from_bytes(bytes) {
|
||||
Ok(file) => {
|
||||
use pelite::pe64::Pe;
|
||||
|
||||
file.resources()?.version_info()
|
||||
}
|
||||
Err(pelite::Error::PeMagic) => {
|
||||
use pelite::pe32::{Pe, PeFile};
|
||||
|
||||
PeFile::from_bytes(bytes)?.resources()?.version_info()
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +86,7 @@ impl<'a> From<&'a str> for Version {
|
||||
Version {
|
||||
release_ids: release.split('.').map(Identifier::from).collect(),
|
||||
pre_release_ids: pre_release
|
||||
.split(is_pre_release_separator)
|
||||
.split_terminator(is_pre_release_separator)
|
||||
.map(Identifier::from)
|
||||
.collect(),
|
||||
}
|
||||
@@ -108,6 +144,42 @@ mod tests {
|
||||
mod empty {
|
||||
use super::super::*;
|
||||
|
||||
#[test]
|
||||
fn version_read_file_version_should_read_the_file_version_field_of_a_32_bit_executable() {
|
||||
let version = Version::read_file_version(Path::new(
|
||||
"loot_api-0.13.8-0-g47797cc_dev-win32/loot_api.dll",
|
||||
)).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
version.release_ids,
|
||||
vec![
|
||||
Identifier::Numeric(0),
|
||||
Identifier::Numeric(13),
|
||||
Identifier::Numeric(8),
|
||||
Identifier::Numeric(0),
|
||||
]
|
||||
);
|
||||
assert!(version.pre_release_ids.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn version_read_file_version_should_read_the_file_version_field_of_a_64_bit_executable() {
|
||||
let version = Version::read_file_version(Path::new(
|
||||
"loot_api-0.13.8-0-g47797cc_dev-win64/loot_api.dll",
|
||||
)).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
version.release_ids,
|
||||
vec![
|
||||
Identifier::Numeric(0),
|
||||
Identifier::Numeric(13),
|
||||
Identifier::Numeric(8),
|
||||
Identifier::Numeric(0),
|
||||
]
|
||||
);
|
||||
assert!(version.pre_release_ids.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn version_eq_an_empty_string_should_equal_an_empty_string() {
|
||||
assert_eq!(Version::from(""), Version::from(""));
|
||||
|
||||
Reference in New Issue
Block a user