use crate::{ResError, ResWriter, util};
const FILE_FLAGS_MASK: u32 = 0x3F; const OS_WIN_NT_32: u32 = 0x40004;
#[derive(Debug)]
pub struct FixedInfo {
pub version: Version,
pub product_version: Version,
pub flags_mask: u32,
pub flags: FileFlags,
pub os: u32,
pub file_type: FileType,
pub sub_type: u32,
}
impl FixedInfo {
pub fn from_env() -> Result<Self, ResError> {
let version = Version::from_env()?;
Ok(FixedInfo {
version: version.clone(),
product_version: version,
flags_mask: FILE_FLAGS_MASK,
flags: FileFlags::from_env()?,
os: OS_WIN_NT_32,
file_type: FileType::App,
sub_type: 0,
})
}
pub(super) fn write(&self, writer: &mut ResWriter) {
writer.line(format_ver("FILEVERSION", &self.version));
writer.line(format_ver("PRODUCTVERSION", &self.product_version));
writer.line(format!("FILEFLAGSMASK {:#X}", self.flags_mask));
writer.line(format!("FILEFLAGS {:#X}", self.flags.val()));
writer.line(format!("FILEOS {:#X}", self.os));
writer.line(format!("FILETYPE {:#X}", self.file_type as u32));
writer.line(format!("FILESUBTYPE {:#X}", self.sub_type));
}
}
impl Default for FixedInfo {
fn default() -> Self {
Self {
version: Version::zero(),
product_version: Version::zero(),
flags_mask: FILE_FLAGS_MASK,
flags: FileFlags::None,
os: 0, file_type: FileType::Unknown,
sub_type: 0,
}
}
}
#[derive(Debug, Clone)]
pub struct Version {
pub major: u16,
pub minor: u16,
pub patch: u16,
pub revision: u16,
}
impl Version {
pub fn new(major: u16, minor: u16, patch: u16, revision: u16) -> Self {
Self {
major,
minor,
patch,
revision,
}
}
pub fn zero() -> Self {
Self::new(0, 0, 0, 0)
}
pub fn from_env() -> Result<Self, ResError> {
Ok(Self::new(
util::env_var("CARGO_PKG_VERSION_MAJOR")?
.parse()
.map_err(|_| ResError::Custom("Failed to parse version! (major)"))?,
util::env_var("CARGO_PKG_VERSION_MINOR")?
.parse()
.map_err(|_| ResError::Custom("Failed to parse version! (minor)"))?,
util::env_var("CARGO_PKG_VERSION_PATCH")?
.parse()
.map_err(|_| ResError::Custom("Failed to parse version! (patch)"))?,
0,
))
}
}
impl std::fmt::Display for Version {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}.{}.{}.{}",
self.major, self.minor, self.patch, self.revision
)
}
}
#[derive(Debug)]
pub enum FileFlags {
None,
Debug,
Patched,
Prerelease,
PrivateBuild,
SpecialBuild,
Combined(u32),
}
impl FileFlags {
pub fn val(&self) -> u32 {
match *self {
Self::None => 0x0,
Self::Debug => 0x1,
Self::Patched => 0x4,
Self::Prerelease => 0x2,
Self::PrivateBuild => 0x8,
Self::SpecialBuild => 0x20,
Self::Combined(v) => v,
}
}
pub fn from_env() -> Result<Self, ResError> {
let mut flags = Self::None;
if util::env_var_os("DEBUG")? == "true" {
flags |= Self::Debug;
}
if !util::env_var_os("CARGO_PKG_VERSION_PRE")?.is_empty() {
flags |= Self::Prerelease;
}
Ok(flags)
}
}
impl std::ops::BitOr for FileFlags {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self::Combined(self.val() | rhs.val())
}
}
impl std::ops::BitOrAssign for FileFlags {
fn bitor_assign(&mut self, rhs: Self) {
*self = Self::Combined(self.val() | rhs.val())
}
}
#[derive(Debug, Clone, Copy)]
pub enum FileType {
Unknown = 0x0,
App = 0x1,
DLL = 0x2,
DRV = 0x3,
Font = 0x4,
VXD = 0x5,
StaticLib = 0x7,
}
fn format_ver(field: &str, version: &Version) -> String {
format!(
"{} {},{},{},{}",
field, version.major, version.minor, version.patch, version.revision
)
}