#[cfg(any(not(feature = "msvc"), not(feature = "gnu")))]
use std::io::ErrorKind;
use std::io::{Error, Seek, Write};
use object::pe::*;
#[cfg(any(feature = "msvc", feature = "gnu"))]
mod ar;
pub mod def;
#[cfg(feature = "gnu")]
mod gnu;
#[cfg(feature = "msvc")]
mod msvc;
#[cfg(feature = "gnu")]
use self::gnu::GnuImportLibrary;
#[cfg(feature = "msvc")]
use self::msvc::MsvcImportLibrary;
use crate::def::ModuleDef;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum MachineType {
I386 = IMAGE_FILE_MACHINE_I386,
ARMNT = IMAGE_FILE_MACHINE_ARMNT,
AMD64 = IMAGE_FILE_MACHINE_AMD64,
ARM64 = IMAGE_FILE_MACHINE_ARM64,
}
impl MachineType {
fn img_rel_relocation(&self) -> u16 {
match self {
Self::AMD64 => IMAGE_REL_AMD64_ADDR32NB,
Self::ARMNT => IMAGE_REL_ARM_ADDR32NB,
Self::ARM64 => IMAGE_REL_ARM64_ADDR32NB,
Self::I386 => IMAGE_REL_I386_DIR32NB,
}
}
}
#[derive(Debug)]
struct ArchiveMember {
name: String,
data: Vec<u8>,
symbols: Vec<String>,
}
impl ArchiveMember {
#[cfg(any(feature = "msvc", feature = "gnu"))]
fn create_archive_entry(self) -> (ar::Header, ArchiveMember) {
let mut header =
ar::Header::new(self.name.to_string().into_bytes(), self.data.len() as u64);
header.set_mode(0o644);
(header, self)
}
}
#[derive(Debug, Clone, Copy)]
pub enum Flavor {
Msvc,
Gnu,
}
#[derive(Debug, Clone)]
pub struct ImportLibrary {
def: ModuleDef,
machine: MachineType,
flavor: Flavor,
}
impl ImportLibrary {
pub fn new(def: &str, machine: MachineType, flavor: Flavor) -> Result<Self, Error> {
let def = ModuleDef::parse(def, machine)?;
Ok(Self::from_def(def, machine, flavor))
}
pub fn from_def(mut def: ModuleDef, machine: MachineType, flavor: Flavor) -> Self {
for export in &mut def.exports {
if let Some(ext_name) = export.ext_name.take() {
export.name = ext_name;
}
}
ImportLibrary {
def,
machine,
flavor,
}
}
pub fn import_name(&self) -> &str {
&self.def.import_name
}
pub fn write_to<W: Write + Seek>(self, writer: &mut W) -> Result<(), Error> {
match self.flavor {
#[cfg(feature = "msvc")]
Flavor::Msvc => MsvcImportLibrary::new(self.def, self.machine).write_to(writer),
#[cfg(not(feature = "msvc"))]
Flavor::Msvc => Err(Error::new(
ErrorKind::Unsupported,
"MSVC import library unsupported, enable 'msvc' feature to use it",
)),
#[cfg(feature = "gnu")]
Flavor::Gnu => GnuImportLibrary::new(self.def, self.machine).write_to(writer),
#[cfg(not(feature = "gnu"))]
Flavor::Gnu => Err(Error::new(
ErrorKind::Unsupported,
"GNU import library unsupported, enable 'gnu' feature to use it",
)),
}
}
}