extern crate alloc;
use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
use core::ffi::c_int;
use crate::raw::{ExecFlags, ExtraParameters, StackNode};
use crate::tchar::{self, Tchar};
use crate::{Nsis, VAR_COUNT, Var};
pub struct TestInstaller {
head: Box<*mut StackNode>,
vars: Box<[Tchar]>,
flags: Box<ExecFlags>,
extra: Box<ExtraParameters>,
string_size: usize,
}
impl TestInstaller {
#[must_use]
pub fn new(string_size: usize) -> Self {
let mut flags = Box::new(ExecFlags {
plugin_api_version: crate::NSISPIAPIVER_CURR,
..ExecFlags::default()
});
let extra = Box::new(ExtraParameters {
exec_flags: &raw mut *flags,
execute_code_segment: None,
validate_filename: None,
register_plugin_callback: None,
});
Self {
head: Box::new(core::ptr::null_mut()),
vars: vec![0 as Tchar; VAR_COUNT * string_size].into_boxed_slice(),
flags,
extra,
string_size,
}
}
#[must_use]
pub fn stock() -> Self {
Self::new(1024)
}
#[must_use]
pub fn long_string() -> Self {
Self::new(8192)
}
#[must_use]
pub fn string_size(&self) -> usize {
self.string_size
}
#[must_use]
pub fn nsis(&mut self) -> Nsis {
unsafe {
Nsis::from_raw(
core::ptr::null_mut(),
self.string_size as c_int,
self.vars.as_mut_ptr(),
&raw mut *self.head,
&raw mut *self.extra,
)
}
}
pub fn call(&mut self, export: crate::raw::Export) {
unsafe {
export(
core::ptr::null_mut(),
self.string_size as c_int,
self.vars.as_mut_ptr(),
&raw mut *self.head,
&raw mut *self.extra,
);
}
}
pub fn push(&mut self, value: &str) {
let _ = self.nsis().stack.push(value);
}
pub fn pop(&mut self) -> Option<String> {
self.nsis().stack.pop().ok()
}
#[must_use]
pub fn stack(&self) -> Vec<String> {
let mut out = Vec::new();
let mut node = *self.head;
while !node.is_null() {
let text = unsafe { (&raw const (*node).text).cast::<Tchar>() };
out.push(unsafe { tchar::read_bounded(text, self.string_size) });
node = unsafe { (*node).next };
}
out
}
#[must_use]
pub fn is_empty(&self) -> bool {
(*self.head).is_null()
}
#[must_use]
pub fn var(&self, var: Var) -> String {
let offset = var.index() * self.string_size;
unsafe { tchar::read_bounded(self.vars.as_ptr().add(offset), self.string_size) }
}
pub fn set_var(&mut self, var: Var, value: &str) {
let _ = self.nsis().vars.set(var, value);
}
#[must_use]
pub fn flags(&self) -> &ExecFlags {
&self.flags
}
pub fn flags_mut(&mut self) -> &mut ExecFlags {
&mut self.flags
}
#[must_use]
pub fn error(&self) -> bool {
self.flags.exec_error != 0
}
pub fn clear_error(&mut self) {
self.flags.exec_error = 0;
}
pub fn extra_mut(&mut self) -> &mut ExtraParameters {
&mut self.extra
}
}
impl Drop for TestInstaller {
fn drop(&mut self) {
let mut node = *self.head;
while !node.is_null() {
let next = unsafe { (*node).next };
unsafe { crate::sys::free(node.cast()) };
node = next;
}
}
}