hwid 0.1.0

Resolve unique hardware-based identifiers for a system
use std::io::{Error, ErrorKind};

use crate::smbios::SMBiosData;

use super::WinSMBiosData;

use windows::Win32::System::SystemInformation::{GetSystemFirmwareTable, RSMB};

/// Calls the Windows kernel32 function [GetSystemFirmwareTable](https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemfirmwaretable)
pub fn load_windows_smbios_data() -> Result<WinSMBiosData, Error> {
    match raw_smbios_from_device() {
        Ok(raw) => WinSMBiosData::new(raw),
        Err(e) => Err(e),
    }
}

/// Loads SMBIOS table data ([SMBiosData]) from the device
pub fn table_load_from_device() -> Result<SMBiosData, Error> {
    Ok(load_windows_smbios_data()?.smbios_data)
}

/// Returns smbios raw data
pub fn raw_smbios_from_device() -> Result<Vec<u8>, Error> {
    let max_i32 = i32::MAX as u32;

    let buffer_size = unsafe { GetSystemFirmwareTable(RSMB, 0, None) };

    if buffer_size == 0 {
        return Err(Error::last_os_error());
    } else if buffer_size > max_i32 {
        return Err(Error::new(ErrorKind::Other, "Firmware table too large"));
    }

    let mut firmware_table_buffer = vec![0; buffer_size as usize];
    let buffer_size = unsafe { GetSystemFirmwareTable(RSMB, 0, Some(&mut firmware_table_buffer)) };

    if buffer_size == 0 {
        Err(Error::last_os_error())
    } else if buffer_size > max_i32 {
        Err(Error::new(ErrorKind::Other, "Firmware table too large"))
    } else {
        Ok(firmware_table_buffer)
    }
}