mod copy_mode;
mod flags;
mod r#type;
mod verification;
use std::io;
pub use copy_mode::FileCopyMode;
use encoding_rs::Encoding;
pub use flags::FileFlags;
pub use r#type::FileType;
pub use verification::FileVerification;
use zerocopy::LE;
use crate::{
entry::Condition,
header::flag_reader::read_flags::read_flags,
read::ReadBytesExt,
version::{InnoVersion, windows_version::WindowsVersionRange},
};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct File {
source: Option<String>,
destination: Option<String>,
install_font_name: Option<String>,
strong_assembly_name: Option<String>,
excludes: Option<String>,
download_is_sig_source: Option<String>,
download_user_name: Option<String>,
download_password: Option<String>,
extract_archive_password: Option<String>,
verification: Option<FileVerification>,
location: u32,
attributes: u32,
external_size: u64,
permission: i16,
flags: FileFlags,
r#type: FileType,
}
impl File {
pub fn read<R>(
mut reader: R,
codepage: &'static Encoding,
version: InnoVersion,
) -> io::Result<Self>
where
R: io::Read,
{
if version < 1.3 {
let _uncompressed_size = reader.read_u32::<LE>()?;
}
let mut file = Self {
source: reader.read_decoded_pascal_string(codepage)?,
destination: reader.read_decoded_pascal_string(codepage)?,
install_font_name: reader.read_decoded_pascal_string(codepage)?,
..Self::default()
};
if version >= (5, 2, 5) {
file.strong_assembly_name = reader.read_decoded_pascal_string(codepage)?;
}
Condition::read(&mut reader, codepage, version)?;
if version >= 6.5 {
file.excludes = reader.read_decoded_pascal_string(codepage)?;
file.download_is_sig_source = reader.read_decoded_pascal_string(codepage)?;
file.download_user_name = reader.read_decoded_pascal_string(codepage)?;
file.download_password = reader.read_decoded_pascal_string(codepage)?;
file.extract_archive_password = reader.read_decoded_pascal_string(codepage)?;
file.verification = Some(FileVerification::read(&mut reader, codepage)?);
}
WindowsVersionRange::read_from(&mut reader, version)?;
file.location = reader.read_u32::<LE>()?;
file.attributes = reader.read_u32::<LE>()?;
file.external_size = if version >= 4 {
reader.read_u64::<LE>()?
} else {
reader.read_u32::<LE>()?.into()
};
if version < (3, 0, 5) {
file.flags |= FileFlags::from(FileCopyMode::try_read_from_io(&mut reader)?);
}
if version >= 4.1 {
file.permission = reader.read_i16::<LE>()?;
}
file.flags |= read_flags!(&mut reader,
[
FileFlags::CONFIRM_OVERWRITE,
FileFlags::NEVER_UNINSTALL,
FileFlags::RESTART_REPLACE,
FileFlags::DELETE_AFTER_INSTALL,
FileFlags::REGISTER_SERVER,
FileFlags::REGISTER_TYPE_LIB,
FileFlags::SHARED_FILE,
],
if version < 2 && !version.is_isx() => FileFlags::IS_README_FILE,
[FileFlags::COMPARE_TIME_STAMP, FileFlags::FONT_IS_NOT_TRUE_TYPE],
if version >= (1, 2, 5) => FileFlags::SKIP_IF_SOURCE_DOESNT_EXIST,
if version >= (1, 2, 6) => FileFlags::OVERWRITE_READ_ONLY,
if version >= (1, 3, 21) => [
FileFlags::OVERWRITE_SAME_VERSION,
FileFlags::CUSTOM_DEST_NAME
],
if version >= (1, 3, 25) => FileFlags::ONLY_IF_DEST_FILE_EXISTS,
if version >= (2, 0, 5) => FileFlags::NO_REG_ERROR,
if version >= (3, 0, 1) => FileFlags::UNINS_RESTART_DELETE,
if version >= (3, 0, 5) => [
FileFlags::ONLY_IF_DOESNT_EXIST,
FileFlags::IGNORE_VERSION,
FileFlags::PROMPT_IF_OLDER,
],
if version >= 4 || (version.is_isx() && version >= (3, 0, 6)) => FileFlags::DONT_COPY,
if version >= (4, 0, 5) => FileFlags::UNINS_REMOVE_READ_ONLY,
if version >= (4, 1, 8) => FileFlags::RECURSE_SUB_DIRS_EXTERNAL,
if version >= (4, 2, 1) => FileFlags::REPLACE_SAME_VERSION_IF_CONTENTS_DIFFER,
if version >= (4, 2, 5) => FileFlags::DONT_VERIFY_CHECKSUM,
if version >= (5, 0, 3) => FileFlags::UNINS_NO_SHARED_FILE_PROMPT,
if version >= 5.1 => FileFlags::CREATE_ALL_SUB_DIRS,
if version >= (5, 1, 2) => FileFlags::BITS_32, FileFlags::BITS_64,
if version >= 5.2 => [
FileFlags::EXTERNAL_SIZE_PRESET,
FileFlags::SET_NTFS_COMPRESSION,
FileFlags::UNSET_NTFS_COMPRESSION,
],
if version >= (5, 2, 5) => FileFlags::GAC_INSTALL,
if version >= 6.5 => [FileFlags::DOWNLOAD, FileFlags::EXTRACT_ARCHIVE],
pad if version >= 6.7 => 8,
)?;
file.r#type = FileType::try_read_from_io(&mut reader)?;
Ok(file)
}
#[must_use]
#[inline]
pub fn source(&self) -> Option<&str> {
self.source.as_deref()
}
#[must_use]
#[inline]
pub fn destination(&self) -> Option<&str> {
self.destination.as_deref()
}
#[must_use]
#[inline]
pub fn install_font_name(&self) -> Option<&str> {
self.install_font_name.as_deref()
}
#[must_use]
#[inline]
pub fn strong_assembly_name(&self) -> Option<&str> {
self.strong_assembly_name.as_deref()
}
#[must_use]
#[inline]
pub const fn location(&self) -> u32 {
self.location
}
#[must_use]
#[inline]
pub const fn attributes(&self) -> u32 {
self.attributes
}
#[must_use]
#[inline]
pub const fn external_size(&self) -> u64 {
self.external_size
}
#[must_use]
#[inline]
pub const fn permission(&self) -> i16 {
self.permission
}
#[must_use]
#[inline]
pub const fn flags(&self) -> FileFlags {
self.flags
}
#[must_use]
#[inline]
pub const fn r#type(&self) -> FileType {
self.r#type
}
}
impl Default for File {
fn default() -> Self {
Self {
source: None,
destination: None,
install_font_name: None,
strong_assembly_name: None,
excludes: None,
download_is_sig_source: None,
download_user_name: None,
download_password: None,
extract_archive_password: None,
verification: None,
location: 0,
attributes: 0,
external_size: 0,
permission: -1,
flags: FileFlags::default(),
r#type: FileType::default(),
}
}
}