mirror of
https://codeberg.org/unspeaker/vestal.git
synced 2025-12-06 08:36:41 +01:00
use object to parse and add jack stub
This commit is contained in:
parent
686f47a3cf
commit
10c922e0c5
8 changed files with 281 additions and 1355 deletions
1315
Cargo.lock
generated
1315
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -4,11 +4,11 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[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" ] }
|
||||
lancelot = "0.9.7"
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,20 @@
|
|||
#![feature(slice_split_once)]
|
||||
mod dll;
|
||||
mod exec;
|
||||
mod util;
|
||||
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::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 lancelot::loader::pe::{PE, reloc::apply_relocations};
|
||||
pub(crate) use goblin::{error, Object, pe::{import::Import, export::Export}};
|
||||
pub(crate) use object::read::pe::PeFile;
|
||||
pub(crate) use object::write::elf::Writer as ElfWriter;
|
||||
//pub(crate) use ::lancelot::loader::pe::{PE, reloc::apply_relocations};
|
||||
//pub(crate) use ::goblin::{error, Object, pe::{import::Import, export::Export}};
|
||||
pub(crate) use ::object::endian::LittleEndian;
|
||||
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};
|
||||
type Usually<T> = Result<T, Box<dyn std::error::Error>>;
|
||||
fn main () -> Usually<()> {
|
||||
|
|
@ -18,17 +24,110 @@ fn main () -> Usually<()> {
|
|||
//.arg(arg!(-s --stub <VALUE> "Provide stub import").required(false))
|
||||
.get_matches();
|
||||
if let Some(path) = matches.get_one::<PathBuf>("path") {
|
||||
relink(path)
|
||||
//let mut context = crate::dll::PEContext::default();
|
||||
//context.load("main", &canonicalize(&path)?)?;
|
||||
//crate::exec::relink(&context)?;
|
||||
let mut vestal = Vestal::default();
|
||||
vestal.search_paths.push(std::env::current_dir()?);
|
||||
vestal.search_paths.push("/home/user/Lab/Cosmo/wineprefix/drive_c/windows/system32".into());
|
||||
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 {
|
||||
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(())
|
||||
}
|
||||
#[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
13
crates/vestal/src/util.rs
Normal 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())
|
||||
}
|
||||
}
|
||||
|
|
@ -7,4 +7,5 @@ edition = "2021"
|
|||
crate-type = ["cdylib"]
|
||||
|
||||
[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" }
|
||||
|
|
|
|||
|
|
@ -1,49 +1,8 @@
|
|||
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
|
||||
}
|
||||
use tek_jack::{*, jack::*};
|
||||
use std::error::Error;
|
||||
pub fn main () -> Result<(), Box<dyn Error>> {
|
||||
let jack = Jack::new("vestal")?.run(|jack|Ok(Host(jack.clone())))?;
|
||||
Ok(())
|
||||
}
|
||||
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);
|
||||
struct Host(Jack);
|
||||
audio!(|self: Host, _c, _s|Control::Continue);
|
||||
|
|
|
|||
96
crates/wrapper/src/nih.rs
Normal file
96
crates/wrapper/src/nih.rs
Normal 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);
|
||||
Loading…
Add table
Add a link
Reference in a new issue