use object to parse and add jack stub

This commit is contained in:
🪞👃🪞 2025-02-19 22:55:09 +02:00
parent 686f47a3cf
commit 10c922e0c5
8 changed files with 281 additions and 1355 deletions

1315
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -4,11 +4,11 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
object = { version = "0.36.7", features = [ "read_core", "write_core", "elf", "pe" ] }
exe = "0.5.6"
elf = "0.7.4"
goblin = "0.9.3"
clap = { version = "4.5.4", features = [ "cargo" ] } clap = { version = "4.5.4", features = [ "cargo" ] }
lancelot = "0.9.7"
syscalls = "0.6.18" syscalls = "0.6.18"
object = { version = "0.36.7", features = [ "read_core", "write_core", "elf", "pe" ] }
#exe = "0.5.6"
#elf = "0.7.4"
#goblin = "0.9.3"
#lancelot = "0.9.7"
#falcon = "0.5.5" #falcon = "0.5.5"

View file

@ -136,16 +136,3 @@ impl Default for AEffect {
} }
} }
} }
/// You can manually patch DLLs by prepending
/// a `#!/usr/bin/env vestal` line to them.
pub fn slice_shebang (buffer: &[u8]) -> (Vec<u8>, Vec<u8>) {
if buffer.get(0) == Some(&b'#') && buffer.get(1) == Some(&b'!') {
if let Some((bang, data)) = buffer.split_once(|x|*x==0x0a) {
(bang.to_vec(), data.to_vec())
} else {
(buffer.to_vec(), vec![])
}
} else {
(vec![], buffer.to_vec())
}
}

View file

@ -1,14 +1,20 @@
#![feature(slice_split_once)] #![feature(slice_split_once)]
mod dll; mod util;
mod exec; pub(crate) use self::util::*;
//mod dll;
//mod exec;
pub(crate) use std::pin::Pin;
pub(crate) use std::sync::Arc;
pub(crate) use std::error::Error; pub(crate) use std::error::Error;
pub(crate) use std::path::{Path, PathBuf}; pub(crate) use std::path::{Path, PathBuf};
pub(crate) use std::collections::HashMap; pub(crate) use std::collections::{HashMap, HashSet};
pub(crate) use std::fs::{read, canonicalize}; pub(crate) use std::fs::{read, canonicalize};
pub(crate) use lancelot::loader::pe::{PE, reloc::apply_relocations}; //pub(crate) use ::lancelot::loader::pe::{PE, reloc::apply_relocations};
pub(crate) use goblin::{error, Object, pe::{import::Import, export::Export}}; //pub(crate) use ::goblin::{error, Object, pe::{import::Import, export::Export}};
pub(crate) use object::read::pe::PeFile; pub(crate) use ::object::endian::LittleEndian;
pub(crate) use object::write::elf::Writer as ElfWriter; pub(crate) use ::object::pe::ImageNtHeaders64;
pub(crate) use ::object::read::pe::PeFile;
pub(crate) use ::object::write::elf::Writer as ElfWriter;
use clap::{arg, command, value_parser, ArgAction, Command}; use clap::{arg, command, value_parser, ArgAction, Command};
type Usually<T> = Result<T, Box<dyn std::error::Error>>; type Usually<T> = Result<T, Box<dyn std::error::Error>>;
fn main () -> Usually<()> { fn main () -> Usually<()> {
@ -18,17 +24,110 @@ fn main () -> Usually<()> {
//.arg(arg!(-s --stub <VALUE> "Provide stub import").required(false)) //.arg(arg!(-s --stub <VALUE> "Provide stub import").required(false))
.get_matches(); .get_matches();
if let Some(path) = matches.get_one::<PathBuf>("path") { if let Some(path) = matches.get_one::<PathBuf>("path") {
relink(path) let mut vestal = Vestal::default();
//let mut context = crate::dll::PEContext::default(); vestal.search_paths.push(std::env::current_dir()?);
//context.load("main", &canonicalize(&path)?)?; vestal.search_paths.push("/home/user/Lab/Cosmo/wineprefix/drive_c/windows/system32".into());
//crate::exec::relink(&context)?; if let Some(path) = vestal.resolve(path.to_str().expect("path must be unicode"))? {
vestal.load(&path)?;
vestal.inspect();
} else {
panic!("Could not find: {path:?}")
}
} else { } else {
panic!("Pass a path to a VST DLL.") panic!("Pass a path to a VST DLL.")
} }
}
fn relink (path: &PathBuf) -> Usually<()> {
let (bang, data) = crate::dll::slice_shebang(read(path)?.as_slice());
let pe = PeFile::parse(data.as_slice())?;
Ok(()) Ok(())
} }
#[derive(Default, Debug)]
struct Vestal {
search_paths: Vec<PathBuf>,
paths_visited: HashSet<Arc<PathBuf>>,
path_to_bang: HashMap<Arc<PathBuf>, Arc<[u8]>>,
path_to_data: HashMap<Arc<PathBuf>, Arc<[u8]>>,
path_to_exports: HashMap<Arc<PathBuf>, Vec<Export>>,
path_to_imports: HashMap<Arc<PathBuf>, Vec<Import>>,
}
#[derive(Debug)]
struct Export {}
#[derive(Debug)]
struct Import {}
impl Vestal {
fn resolve (&self, name: &str) -> Usually<Option<PathBuf>> {
for base in self.search_paths.iter() {
let mut path = base.clone();
path.push(name.to_lowercase());
if std::fs::exists(&path)? {
return Ok(Some(canonicalize(&path)?))
}
}
Ok(None)
}
fn load (&mut self, path: &PathBuf) -> Usually<()> {
if !self.paths_visited.contains(path) {
let path = Arc::new(path.clone());
println!("(load {path:?})");
self.paths_visited.insert(path.clone());
let (bang, data) = slice_shebang(read(path.as_path())?.as_slice());
self.path_to_bang.insert(path.clone(), bang.into());
self.path_to_data.insert(path.clone(), data.clone().into());
let dll: PeFile<'_, ImageNtHeaders64, &[u8]> = PeFile::parse(data.as_slice())?;
if let Some(exports) = dll.export_table()? {
let mut collected = vec![];
for export in exports.exports()?.iter() {
collected.push(Export {});
if let Some(name) = export.name {
let name = String::from_utf8(name.to_vec())?;
//println!(" (export {} {:?} {:?})", &export.ordinal, &name, &export.target);
} else {
//println!(" (export {} <nameless> {:?})", &export.ordinal, &export.target)
}
}
self.path_to_exports.insert(path.clone(), collected);
}
if let Some(imports) = dll.import_table()? {
let mut collected = vec![];
for import in imports.descriptors()? {
let name = imports.name(import?.name.get(LittleEndian))?.to_vec();
let name = String::from_utf8(name.to_vec())?;
let name = name.to_lowercase();
if let Some(path) = self.resolve(&name)? {
if !self.paths_visited.contains(&path) {
//println!("(import {name:?})");
self.load(&path)?;
}
} else {
panic!("not found: {name:?}");
}
}
self.path_to_imports.insert(path.clone(), collected);
}
}
Ok(())
}
fn inspect (&self) {
for path in self.search_paths.iter() {
println!("(search {path:?})")
}
for path in self.paths_visited.iter() {
println!("(visited {path:?})")
}
for (path, bang) in self.path_to_bang.iter() {
if bang.len() > 0 {
println!("(bang {path:?} {:x})", bang.len())
}
}
for (path, data) in self.path_to_data.iter() {
println!("(buffer {:p} 0x{:08x} {path:?})", data.as_ptr(), data.len())
}
for (path, exports) in self.path_to_exports.iter() {
//println!("(exports {path:?}\n {exports:?})")
}
for (path, imports) in self.path_to_imports.iter() {
//print!("(imports {path:?}");
//for import in imports.iter() {
//print!("\n {import:?}");
//}
//println!(")");
}
}
}

13
crates/vestal/src/util.rs Normal file
View file

@ -0,0 +1,13 @@
/// You can manually patch DLLs by prepending
/// a `#!/usr/bin/env vestal` line to them.
pub fn slice_shebang (buffer: &[u8]) -> (Vec<u8>, Vec<u8>) {
if buffer.get(0) == Some(&b'#') && buffer.get(1) == Some(&b'!') {
if let Some((bang, data)) = buffer.split_once(|x|*x==0x0a) {
(bang.to_vec(), data.to_vec())
} else {
(buffer.to_vec(), vec![])
}
} else {
(vec![], buffer.to_vec())
}
}

View file

@ -7,4 +7,5 @@ edition = "2021"
crate-type = ["cdylib"] crate-type = ["cdylib"]
[dependencies] [dependencies]
nih_plug = { git = "https://github.com/robbert-vdh/nih-plug" } #nih_plug = { git = "https://github.com/robbert-vdh/nih-plug" }
tek_jack = { git = "https://codeberg.org/unspeaker/tek", ref = "77d617f9" }

View file

@ -1,49 +1,8 @@
use std::sync::Arc; use tek_jack::{*, jack::*};
use nih_plug::prelude::*; use std::error::Error;
#[derive(Default)] pub struct VestalWrapper { params: Arc<VestalWrapperParams> } pub fn main () -> Result<(), Box<dyn Error>> {
#[derive(Default, Clone, Params)] struct VestalWrapperParams {} let jack = Jack::new("vestal")?.run(|jack|Ok(Host(jack.clone())))?;
impl Plugin for VestalWrapper { Ok(())
const NAME: &'static str = "VESTAL";
const VENDOR: &'static str = "AUTHOR";
const URL: &'static str = env!("CARGO_PKG_HOMEPAGE");
const EMAIL: &'static str = "EMAIL";
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const AUDIO_IO_LAYOUTS: &'static [AudioIOLayout] = &[];
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
type SysExMessage = ();
type BackgroundTask = ();
fn params (&self) -> Arc<dyn Params> {
self.params.clone()
}
fn editor (&mut self, _async_executor: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> {
None
}
fn initialize (
&mut self, _: &AudioIOLayout, _: &BufferConfig, _: &mut impl InitContext<Self>,
) -> bool {
todo!("initialize");
true
}
fn reset (&mut self) {
todo!("reset");
}
fn process (
&mut self, _: &mut Buffer, _: &mut AuxiliaryBuffers, _: &mut impl ProcessContext<Self>
) -> ProcessStatus {
todo!("process");
ProcessStatus::Normal
}
} }
impl ClapPlugin for VestalWrapper { struct Host(Jack);
const CLAP_ID: &'static str = "ID"; audio!(|self: Host, _c, _s|Control::Continue);
const CLAP_DESCRIPTION: Option<&'static str> = Some("DESC");
const CLAP_MANUAL_URL: Option<&'static str> = Some(Self::URL);
const CLAP_SUPPORT_URL: Option<&'static str> = None;
const CLAP_FEATURES: &'static [ClapFeature] = &[];
}
impl Vst3Plugin for VestalWrapper {
const VST3_CLASS_ID: [u8; 16] = *b"VESTAL_________.";
const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] = &[];
}
nih_export_clap!(VestalWrapper);
nih_export_vst3!(VestalWrapper);

96
crates/wrapper/src/nih.rs Normal file
View file

@ -0,0 +1,96 @@
use std::sync::Arc;
use nih_plug::prelude::*;
#[derive(Default)] pub struct VestalWrapper { params: Arc<VestalWrapperParams> }
#[derive(Default, Clone, Params)] struct VestalWrapperParams {}
impl Plugin for VestalWrapper {
const NAME: &'static str = "VESTAL";
const VENDOR: &'static str = "AUTHOR";
const URL: &'static str = env!("CARGO_PKG_HOMEPAGE");
const EMAIL: &'static str = "EMAIL";
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const AUDIO_IO_LAYOUTS: &'static [AudioIOLayout] = &[];
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
type SysExMessage = ();
type BackgroundTask = ();
fn params (&self) -> Arc<dyn Params> {
self.params.clone()
}
fn editor (&mut self, _async_executor: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> {
None
}
fn initialize (
&mut self, _: &AudioIOLayout, _: &BufferConfig, _: &mut impl InitContext<Self>,
) -> bool {
todo!("initialize");
true
}
fn reset (&mut self) {
todo!("reset");
}
fn process (
&mut self, _: &mut Buffer, _: &mut AuxiliaryBuffers, _: &mut impl ProcessContext<Self>
) -> ProcessStatus {
todo!("process");
ProcessStatus::Normal
}
}
impl ClapPlugin for VestalWrapper {
const CLAP_ID: &'static str = "ID";
const CLAP_DESCRIPTION: Option<&'static str> = Some("DESC");
const CLAP_MANUAL_URL: Option<&'static str> = Some(Self::URL);
const CLAP_SUPPORT_URL: Option<&'static str> = None;
const CLAP_FEATURES: &'static [ClapFeature] = &[];
}
impl Vst3Plugin for VestalWrapper {
const VST3_CLASS_ID: [u8; 16] = *b"VESTAL_________.";
const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] = &[];
}
nih_export_clap!(VestalWrapper);
nih_export_vst3!(VestalWrapper);
#[derive(Default)] pub struct VestalWrapper { params: Arc<VestalWrapperParams> }
#[derive(Default, Clone, Params)] struct VestalWrapperParams {}
impl Plugin for VestalWrapper {
const NAME: &'static str = "VESTAL";
const VENDOR: &'static str = "AUTHOR";
const URL: &'static str = env!("CARGO_PKG_HOMEPAGE");
const EMAIL: &'static str = "EMAIL";
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const AUDIO_IO_LAYOUTS: &'static [AudioIOLayout] = &[];
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
type SysExMessage = ();
type BackgroundTask = ();
fn params (&self) -> Arc<dyn Params> {
self.params.clone()
}
fn editor (&mut self, _async_executor: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> {
None
}
fn initialize (
&mut self, _: &AudioIOLayout, _: &BufferConfig, _: &mut impl InitContext<Self>,
) -> bool {
todo!("initialize");
true
}
fn reset (&mut self) {
todo!("reset");
}
fn process (
&mut self, _: &mut Buffer, _: &mut AuxiliaryBuffers, _: &mut impl ProcessContext<Self>
) -> ProcessStatus {
todo!("process");
ProcessStatus::Normal
}
}
impl ClapPlugin for VestalWrapper {
const CLAP_ID: &'static str = "ID";
const CLAP_DESCRIPTION: Option<&'static str> = Some("DESC");
const CLAP_MANUAL_URL: Option<&'static str> = Some(Self::URL);
const CLAP_SUPPORT_URL: Option<&'static str> = None;
const CLAP_FEATURES: &'static [ClapFeature] = &[];
}
impl Vst3Plugin for VestalWrapper {
const VST3_CLASS_ID: [u8; 16] = *b"VESTAL_________.";
const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] = &[];
}
nih_export_clap!(VestalWrapper);
nih_export_vst3!(VestalWrapper);