use super::{arg_dword, read_cstr_local, HostState, Registry, StubFn, Win32Error};
use crate::emulator::{Cpu, Mmu};
const ERROR_FILE_NOT_FOUND: u32 = 2;
const ERROR_SUCCESS: u32 = 0;
const HKEY_FPU: u32 = 0xC0DE_F0F0;
fn key_exists_synthetically(subkey: &str) -> bool {
let s = subkey.to_ascii_lowercase();
let s = s.trim_start_matches('\\');
s == "hardware\\description\\system\\floatingpointprocessor"
|| s.starts_with("hardware\\description\\system\\floatingpointprocessor\\")
}
pub fn register(registry: &mut Registry) {
registry.register(
"advapi32.dll",
"RegCloseKey",
stub_reg_close_key as StubFn,
1,
);
registry.register(
"advapi32.dll",
"RegCreateKeyA",
stub_reg_create_key as StubFn,
3,
);
registry.register(
"advapi32.dll",
"RegCreateKeyExA",
stub_reg_create_key_ex as StubFn,
9,
);
registry.register(
"advapi32.dll",
"RegDeleteKeyA",
stub_reg_delete as StubFn,
2,
);
registry.register(
"advapi32.dll",
"RegDeleteValueA",
stub_reg_delete as StubFn,
2,
);
registry.register(
"advapi32.dll",
"RegEnumKeyExA",
stub_reg_enum_key_ex_a as StubFn,
8,
);
registry.register(
"advapi32.dll",
"RegOpenKeyA",
stub_reg_open_key_a as StubFn,
3,
);
registry.register(
"advapi32.dll",
"RegOpenKeyExA",
stub_reg_open_key_ex_a as StubFn,
5,
);
registry.register(
"advapi32.dll",
"RegQueryValueA",
stub_reg_query_value as StubFn,
4,
);
registry.register(
"advapi32.dll",
"RegQueryValueExA",
stub_reg_query_value_ex as StubFn,
6,
);
registry.register(
"advapi32.dll",
"RegSetValueA",
stub_reg_set_value as StubFn,
5,
);
registry.register(
"advapi32.dll",
"RegSetValueExA",
stub_reg_set_value as StubFn,
6,
);
}
fn stub_reg_close_key(
_cpu: &mut Cpu,
_mmu: &mut Mmu,
_state: &mut HostState,
_registry: &Registry,
) -> Result<u32, Win32Error> {
Ok(ERROR_SUCCESS)
}
fn stub_reg_create_key(
cpu: &mut Cpu,
mmu: &mut Mmu,
_state: &mut HostState,
_registry: &Registry,
) -> Result<u32, Win32Error> {
let _hkey = arg_dword(cpu, mmu, 0).map_err(|t| trap("RegCreateKeyA", t))?;
let _sub = arg_dword(cpu, mmu, 1).map_err(|t| trap("RegCreateKeyA", t))?;
let phk = arg_dword(cpu, mmu, 2).map_err(|t| trap("RegCreateKeyA", t))?;
if phk != 0 {
let _ = mmu.store32(phk, 0xC0DE_8E0F);
}
Ok(ERROR_SUCCESS)
}
fn stub_reg_create_key_ex(
cpu: &mut Cpu,
mmu: &mut Mmu,
_state: &mut HostState,
_registry: &Registry,
) -> Result<u32, Win32Error> {
let phk = arg_dword(cpu, mmu, 6).map_err(|t| trap("RegCreateKeyExA", t))?;
if phk != 0 {
let _ = mmu.store32(phk, 0xC0DE_8E0F);
}
let disposition = arg_dword(cpu, mmu, 7).map_err(|t| trap("RegCreateKeyExA", t))?;
if disposition != 0 {
let _ = mmu.store32(disposition, 2);
}
Ok(ERROR_SUCCESS)
}
fn stub_reg_delete(
_cpu: &mut Cpu,
_mmu: &mut Mmu,
_state: &mut HostState,
_registry: &Registry,
) -> Result<u32, Win32Error> {
Ok(ERROR_SUCCESS)
}
fn stub_reg_enum_key_ex_a(
_cpu: &mut Cpu,
_mmu: &mut Mmu,
_state: &mut HostState,
_registry: &Registry,
) -> Result<u32, Win32Error> {
const ERROR_NO_MORE_ITEMS: u32 = 259;
Ok(ERROR_NO_MORE_ITEMS)
}
fn stub_reg_open_key_a(
cpu: &mut Cpu,
mmu: &mut Mmu,
_state: &mut HostState,
_registry: &Registry,
) -> Result<u32, Win32Error> {
let _hkey = arg_dword(cpu, mmu, 0).map_err(|t| trap("RegOpenKeyA", t))?;
let p_sub = arg_dword(cpu, mmu, 1).map_err(|t| trap("RegOpenKeyA", t))?;
let phk = arg_dword(cpu, mmu, 2).map_err(|t| trap("RegOpenKeyA", t))?;
let sub = if p_sub != 0 {
read_cstr_local(mmu, p_sub, 1024).unwrap_or_default()
} else {
String::new()
};
if key_exists_synthetically(&sub) {
if phk != 0 {
let _ = mmu.store32(phk, HKEY_FPU);
}
return Ok(ERROR_SUCCESS);
}
if phk != 0 {
let _ = mmu.store32(phk, 0);
}
Ok(ERROR_FILE_NOT_FOUND)
}
fn stub_reg_open_key_ex_a(
cpu: &mut Cpu,
mmu: &mut Mmu,
_state: &mut HostState,
_registry: &Registry,
) -> Result<u32, Win32Error> {
let _hkey = arg_dword(cpu, mmu, 0).map_err(|t| trap("RegOpenKeyExA", t))?;
let p_sub = arg_dword(cpu, mmu, 1).map_err(|t| trap("RegOpenKeyExA", t))?;
let _opts = arg_dword(cpu, mmu, 2).map_err(|t| trap("RegOpenKeyExA", t))?;
let _sam = arg_dword(cpu, mmu, 3).map_err(|t| trap("RegOpenKeyExA", t))?;
let phk = arg_dword(cpu, mmu, 4).map_err(|t| trap("RegOpenKeyExA", t))?;
let sub = if p_sub != 0 {
read_cstr_local(mmu, p_sub, 1024).unwrap_or_default()
} else {
String::new()
};
if key_exists_synthetically(&sub) {
if phk != 0 {
let _ = mmu.store32(phk, HKEY_FPU);
}
return Ok(ERROR_SUCCESS);
}
if phk != 0 {
let _ = mmu.store32(phk, 0);
}
Ok(ERROR_FILE_NOT_FOUND)
}
fn stub_reg_query_value(
_cpu: &mut Cpu,
_mmu: &mut Mmu,
_state: &mut HostState,
_registry: &Registry,
) -> Result<u32, Win32Error> {
Ok(ERROR_FILE_NOT_FOUND)
}
fn stub_reg_query_value_ex(
cpu: &mut Cpu,
mmu: &mut Mmu,
_state: &mut HostState,
_registry: &Registry,
) -> Result<u32, Win32Error> {
let pcb = arg_dword(cpu, mmu, 5).map_err(|t| trap("RegQueryValueExA", t))?;
if pcb != 0 {
let _ = mmu.store32(pcb, 0);
}
Ok(ERROR_FILE_NOT_FOUND)
}
fn stub_reg_set_value(
_cpu: &mut Cpu,
_mmu: &mut Mmu,
_state: &mut HostState,
_registry: &Registry,
) -> Result<u32, Win32Error> {
Ok(ERROR_SUCCESS)
}
fn trap(stub: &'static str, t: crate::emulator::Trap) -> Win32Error {
Win32Error::InvalidArgument {
stub,
reason: format!("{t}"),
}
}