pub fn extract_pe_version(bytes: &[u8]) -> Option<String> {
if let Some(v) = try_pe64(bytes) {
return Some(v);
}
try_pe32(bytes)
}
fn try_pe64(bytes: &[u8]) -> Option<String> {
use pelite::pe64::{Pe, PeFile};
let pe = PeFile::from_bytes(bytes).ok()?;
let resources = pe.resources().ok()?;
let version_info = resources.version_info().ok()?;
for language in version_info.translation() {
if let Some(s) = version_info.value(*language, "ProductVersion")
&& !s.is_empty()
{
return Some(normalise(&s));
}
if let Some(s) = version_info.value(*language, "FileVersion")
&& !s.is_empty()
{
return Some(normalise(&s));
}
}
None
}
fn try_pe32(bytes: &[u8]) -> Option<String> {
use pelite::pe32::{Pe, PeFile};
let pe = PeFile::from_bytes(bytes).ok()?;
let resources = pe.resources().ok()?;
let version_info = resources.version_info().ok()?;
for language in version_info.translation() {
if let Some(s) = version_info.value(*language, "ProductVersion")
&& !s.is_empty()
{
return Some(normalise(&s));
}
if let Some(s) = version_info.value(*language, "FileVersion")
&& !s.is_empty()
{
return Some(normalise(&s));
}
}
None
}
fn normalise(s: &str) -> String {
s.trim_end_matches(|c: char| c == '\0' || c.is_whitespace())
.to_string()
}