Add ability to read executable product version field

This commit is contained in:
Oliver Hamlet
2018-10-23 21:12:40 +01:00
parent 5512581c0f
commit 07737cebe8
5 changed files with 94 additions and 12 deletions
+1
View File
@@ -2,6 +2,7 @@
/target/
**/*.rs.bk
Cargo.lock
/tests/7z
/tests/testing-plugins
/tests/loot_api*
/ffi/include/
+3
View File
@@ -27,6 +27,9 @@ before_script:
- 7z x loot_api-0.13.8-0-g47797cc_dev-win64.7z
- mv loot_api-0.13.8-0-g47797cc_dev-win64 loot_api_win64
- wget https://7-zip.org/a/7z1805-extra.7z
- 7z x 7z1805-extra.7z -o7z
- cd ..
script:
+3
View File
@@ -31,6 +31,9 @@ install:
- 7z x loot_api_win64.7z
- mv loot_api-0.13.8-0-g47797cc_dev-win64 loot_api_win64
- ps: (New-Object Net.WebClient).DownloadFile('https://7-zip.org/a/7z1805-extra.7z', "$PWD/7z.7z")
- ps: 7z x "$PWD/7z.7z" -o7z
- cd ..
build: false
+1 -1
View File
@@ -53,7 +53,7 @@ impl fmt::Display for Error {
),
Error::PeParsingError(p, e) => write!(
f,
"An error was encountered while reading the file version field of \"{}\": {}",
"An error was encountered while reading the version fields of \"{}\": {}",
p.display(),
e
),
+86 -11
View File
@@ -1,6 +1,7 @@
use std::cmp::Ordering;
use std::path::Path;
use pelite::image::VS_FIXEDFILEINFO;
use pelite::resources::version_info::VersionInfo;
use pelite::resources::FindError;
use pelite::FileMap;
@@ -29,21 +30,40 @@ pub struct Version {
impl Version {
pub fn read_file_version(file_path: &Path) -> Result<Self, Error> {
Self::read_version(file_path, |f| {
format!(
"{}.{}.{}.{}",
f.dwFileVersion.Major,
f.dwFileVersion.Minor,
f.dwFileVersion.Patch,
f.dwFileVersion.Build
)
})
}
pub fn read_product_version(file_path: &Path) -> Result<Self, Error> {
Self::read_version(file_path, |f| {
format!(
"{}.{}.{}.{}",
f.dwProductVersion.Major,
f.dwProductVersion.Minor,
f.dwProductVersion.Patch,
f.dwProductVersion.Build
)
})
}
fn read_version<F: Fn(&VS_FIXEDFILEINFO) -> String>(
file_path: &Path,
formatter: F,
) -> Result<Self, Error> {
let file_map =
FileMap::open(file_path).map_err(|e| Error::IoError(file_path.to_path_buf(), e))?;
let version_info = get_pe_version_info(file_map.as_ref())
.map_err(|e| Error::PeParsingError(file_path.to_path_buf(), e.into()))?;
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()))
Ok(Version::from(formatter(fixed_file_info).as_str()))
} else {
Ok(Version::from(""))
}
@@ -143,7 +163,7 @@ fn pad_release_ids(ids1: &[Identifier], ids2: &[Identifier]) -> (Vec<Identifier>
#[cfg(test)]
mod tests {
mod empty {
mod constructors {
use super::super::*;
#[test]
@@ -195,9 +215,64 @@ mod tests {
fn version_read_file_version_should_error_with_path_if_the_file_is_not_an_executable() {
let error = Version::read_file_version(Path::new("Cargo.toml")).unwrap_err();
assert_eq!("An error was encountered while reading the file version field of \"Cargo.toml\": bad magic", error.to_string());
assert_eq!("An error was encountered while reading the version fields of \"Cargo.toml\": bad magic", error.to_string());
}
#[test]
fn version_read_product_version_should_read_the_file_version_field_of_a_32_bit_executable()
{
let version = Version::read_product_version(Path::new("tests/7z/7za.exe")).unwrap();
assert_eq!(
version.release_ids,
vec![
Identifier::Numeric(18),
Identifier::Numeric(5),
Identifier::Numeric(0),
Identifier::Numeric(0),
]
);
assert!(version.pre_release_ids.is_empty());
}
#[test]
fn version_read_product_version_should_read_the_file_version_field_of_a_64_bit_executable()
{
let version = Version::read_product_version(Path::new("tests/7z/x64/7za.exe")).unwrap();
assert_eq!(
version.release_ids,
vec![
Identifier::Numeric(18),
Identifier::Numeric(5),
Identifier::Numeric(0),
Identifier::Numeric(0),
]
);
assert!(version.pre_release_ids.is_empty());
}
#[test]
fn version_read_product_version_should_error_with_path_if_path_does_not_exist() {
let error = Version::read_product_version(Path::new("missing")).unwrap_err();
assert!(
error
.to_string()
.starts_with("An error was encountered while accessing the path \"missing\":")
);
}
#[test]
fn version_read_product_version_should_error_with_path_if_the_file_is_not_an_executable() {
let error = Version::read_product_version(Path::new("Cargo.toml")).unwrap_err();
assert_eq!("An error was encountered while reading the version fields of \"Cargo.toml\": bad magic", error.to_string());
}
}
mod empty {
use super::super::*;
#[test]
fn version_eq_an_empty_string_should_equal_an_empty_string() {
assert_eq!(Version::from(""), Version::from(""));