// SPDX-License-Identifier: GPL-3.0-or-later

#include "status-file-dmi.h"

static void dmi_clean_field_placeholder(char *buf, size_t buf_size) {
    if(!buf || !buf_size) return;

    struct {
        const char *found;
        const char *replace;
    } placeholders[] = {
        {"$(DEFAULT_STRING)", ""},
        {"Chassis Manufacture", ""},
        {"Chassis Manufacturer", ""},
        {"Chassis Version", ""},
        {"Default string", ""},
        {"N/A", ""},
        {"NA", ""},
        {"NOT SPECIFIED", ""},
        {"No Enclosure", ""},
        {"None Provided", ""},
        {"None", ""},
        {"OEM Chassis Manufacturer", ""},
        {"OEM Default string000", ""},
        {"OEM", ""},
        {"OEM_MB", ""},
        {"SYSTEM_MANUFACTURER", ""},
        {"SmbiosType1_SystemManufacturer", ""},
        {"SmbiosType2_BoardManufacturer", ""},
        {"Standard", ""},
        {"System Product Name", ""},
        {"System UUID", ""},
        {"System Version", ""},
        {"System manufacturer", ""},
        {"TBD by OEM", ""},
        {"TBD", ""},
        {"To be filled by O.E.M.", ""},
        {"Type2 - Board Manufacturer", ""},
        {"Type2 - Board Vendor Name1", ""},
        {"Unknow", ""},
        {"Unknown", ""},
        {"XXXXX", ""},
        {"default", ""},
        {"empty", ""},
        {"unspecified", ""},
        {"x.x", ""},
        {"(null)", ""},
        {"0123456789", ""},
        {"SKU", ""},
    };

    for (size_t i = 0; i < _countof(placeholders); i++) {
        if (strcasecmp(buf, placeholders[i].found) == 0) {
            strcatz(buf, 0, placeholders[i].replace, buf_size);
            break;
        }
    }
}

static void dmi_clean_field(char *buf, size_t buf_size) {
    if(!buf || !buf_size) return;

    // replace non-ascii characters and control characters with spaces
    for (size_t i = 0; i < buf_size && buf[i]; i++) {
        if (!isascii((uint8_t)buf[i]) || iscntrl((uint8_t)buf[i]))
            buf[i] = ' ';
    }

    // detect if all characters are symbols
    bool contains_alnum = false;
    for (size_t i = 0; i < buf_size && buf[i]; i++) {
        if (isalnum((uint8_t)buf[i])) {
            contains_alnum = true;
            break;
        }
    }

    if (!contains_alnum || !buf[0]) {
        buf[0] = '\0';
        return;
    }

    // remove leading, trailing and duplicate spaces
    trim_all(buf);
    if (!buf[0])
        return;

    dmi_clean_field_placeholder(buf, buf_size);
}

// --------------------------------------------------------------------------------------------------------------------

#if defined(OS_LINUX)
static void linux_get_dmi_field(const char *field, const char *alt, char *dst, size_t dst_size) {
    char filename[FILENAME_MAX];
    dst[0] = '\0';

    if (netdata_configured_host_prefix && *netdata_configured_host_prefix) {
        snprintfz(filename, sizeof(filename), "%s/sys/class/dmi/id/%s", netdata_configured_host_prefix, field);
        if (access(filename, R_OK) != 0) {
            snprintfz(
                filename, sizeof(filename), "%s/sys/devices/virtual/dmi/id/%s", netdata_configured_host_prefix, field);
            if (access(filename, R_OK) != 0)
                filename[0] = '\0';
        }
    } else
        filename[0] = '\0';

    if (!filename[0]) {
        snprintfz(filename, sizeof(filename), "/sys/class/dmi/id/%s", field);
        if (access(filename, R_OK) != 0) {
            snprintfz(filename, sizeof(filename), "/sys/devices/virtual/dmi/id/%s", field);
            if (access(filename, R_OK) != 0) {
                if (alt && *alt) {
                    safecpy(filename, alt);
                    if (access(filename, R_OK) != 0)
                        filename[0] = '\0';
                } else
                    filename[0] = '\0';
            }
        }
    }

    if (!filename[0])
        return;

    size_t buf_size = MAX(256, dst_size);
    CLEAN_CHAR_P *buf = mallocz(buf_size);
    if (read_txt_file(filename, buf, buf_size) != 0)
        return;

    if (!buf[0])
        return;

    dmi_clean_field(buf, buf_size);

    if (!buf[0])
        return;

    // copy it to its final location
    strcatz(dst, 0, buf, dst_size);
}

void os_dmi_info_get(DMI_INFO *dmi) {
    if (!dmi) return;
    
    linux_get_dmi_field("sys_vendor", NULL, dmi->sys.vendor, sizeof(dmi->sys.vendor));
    linux_get_dmi_field("system_serial", NULL, dmi->sys.serial, sizeof(dmi->sys.serial));
    linux_get_dmi_field("product_uuid", NULL, dmi->sys.uuid, sizeof(dmi->sys.uuid));
    linux_get_dmi_field("chassis_asset_tag", NULL, dmi->sys.asset_tag, sizeof(dmi->sys.asset_tag));

    linux_get_dmi_field("product_name", "/proc/device-tree/model", dmi->product.id, sizeof(dmi->product.id));
    if (dmi->product.id[0])
        safecpy(dmi->product.name, dmi->product.id);
    linux_get_dmi_field("product_version", NULL, dmi->product.version, sizeof(dmi->product.version));
    linux_get_dmi_field("product_sku", NULL, dmi->product.sku, sizeof(dmi->product.sku));
    linux_get_dmi_field("product_family", NULL, dmi->product.family, sizeof(dmi->product.family));

    linux_get_dmi_field("chassis_vendor", NULL, dmi->chassis.vendor, sizeof(dmi->chassis.vendor));
    linux_get_dmi_field("chassis_version", NULL, dmi->chassis.version, sizeof(dmi->chassis.version));
    linux_get_dmi_field("chassis_serial", NULL, dmi->chassis.serial, sizeof(dmi->chassis.serial));
    linux_get_dmi_field("chassis_asset_tag", NULL, dmi->chassis.asset_tag, sizeof(dmi->chassis.asset_tag));

    linux_get_dmi_field("board_vendor", NULL, dmi->board.vendor, sizeof(dmi->board.vendor));
    linux_get_dmi_field("board_name", NULL, dmi->board.name, sizeof(dmi->board.name));
    linux_get_dmi_field("board_version", NULL, dmi->board.version, sizeof(dmi->board.version));
    linux_get_dmi_field("board_serial", NULL, dmi->board.serial, sizeof(dmi->board.serial));
    linux_get_dmi_field("board_asset_tag", NULL, dmi->board.asset_tag, sizeof(dmi->board.asset_tag));

    linux_get_dmi_field("bios_vendor", NULL, dmi->bios.vendor, sizeof(dmi->bios.vendor));
    linux_get_dmi_field("bios_version", NULL, dmi->bios.version, sizeof(dmi->bios.version));
    linux_get_dmi_field("bios_date", NULL, dmi->bios.date, sizeof(dmi->bios.date));
    linux_get_dmi_field("bios_release", NULL, dmi->bios.release, sizeof(dmi->bios.release));

    linux_get_dmi_field("chassis_type", NULL, dmi->chassis.type, sizeof(dmi->chassis.type));
    
}
#elif defined(OS_MACOS)

#include <IOKit/IOKitLib.h>
#include <CoreFoundation/CoreFoundation.h>
#include <fcntl.h>
#include <poll.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <unistd.h>

#if defined(MAC_OS_VERSION_12_0) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_12_0
#define NETDATA_IOKIT_MAIN_PORT kIOMainPortDefault
#else
#define NETDATA_IOKIT_MAIN_PORT kIOMasterPortDefault
#endif

struct macos_model_name {
    const char *id;
    const char *name;
};

/*
 * Mac model names from MacAdmins SOFA v2 macOS data feed.
 * Feed version: 2.0; LastCheck: 2026-07-05T07:39:47.975742456+00:00.
 * Source: https://sofafeed.macadmins.io/v2/macos_data_feed.json
 */
static const struct macos_model_name macos_known_models[] = {
    {"Mac13,1", "Mac Studio (M1 Max)"},
    {"Mac13,2", "Mac Studio (M1 Ultra)"},
    {"Mac14,2", "MacBook Air (M2, 2022)"},
    {"Mac14,3", "Mac mini (M2, 2023)"},
    {"Mac14,5", "MacBook Pro (14-inch, M2 Max, 2023)"},
    {"Mac14,6", "MacBook Pro (16-inch, M2 Max, 2023)"},
    {"Mac14,7", "MacBook Pro (13-inch, M2, 2022)"},
    {"Mac14,8", "Mac Pro (Rack, 2023)"},
    {"Mac14,9", "MacBook Pro (14-inch, M2 Pro, 2023)"},
    {"Mac14,10", "MacBook Pro (16-inch, M2 Pro, 2023)"},
    {"Mac14,12", "Mac mini (M2 Pro, 2023)"},
    {"Mac14,13", "Mac Studio (M2 Max, 2023)"},
    {"Mac14,14", "Mac Studio (M2 Ultra, 2023)"},
    {"Mac14,15", "MacBook Air (15-inch, M2, 2023)"},
    {"Mac15,3", "MacBook Pro (14-inch, M3, Nov 2023)"},
    {"Mac15,4", "iMac (24-inch, M3, 2023, Two Ports)"},
    {"Mac15,5", "iMac (24-inch, M3, 2023, Four Ports)"},
    {"Mac15,6", "MacBook Pro (14-inch, M3 Pro, Nov 2023)"},
    {"Mac15,7", "MacBook Pro (16-inch, M3 Pro, Nov 2023)"},
    {"Mac15,8", "MacBook Pro (14-inch, 16-core M3 Max, Nov 2023)"},
    {"Mac15,9", "MacBook Pro (16-inch, 16-core M3 Max, Nov 2023)"},
    {"Mac15,10", "MacBook Pro (14-inch, 14-core M3 Max, Nov 2023)"},
    {"Mac15,11", "MacBook Pro (16-inch, 14-core M3 Max, Nov 2023)"},
    {"Mac15,12", "MacBook Air (13-inch, M3, 2024)"},
    {"Mac15,13", "MacBook Air (15-inch, M3, 2024)"},
    {"Mac15,14", "Mac Studio (M3 Ultra, 2025)"},
    {"Mac16,1", "MacBook Pro (14-inch, M4, Nov 2024)"},
    {"Mac16,2", "iMac (24-inch, M4, 2024, Two Ports)"},
    {"Mac16,3", "iMac (24-inch, M4, 2024, Four Ports)"},
    {"Mac16,5", "MacBook Pro (16-inch, M4 Max, Nov 2024)"},
    {"Mac16,6", "MacBook Pro (14-inch, M4 Max, Nov 2024)"},
    {"Mac16,7", "MacBook Pro (16-inch, M4 Pro, Nov 2024)"},
    {"Mac16,8", "MacBook Pro (14-inch, M4 Pro, Nov 2024)"},
    {"Mac16,9", "Mac Studio (M4 Max, 2025)"},
    {"Mac16,10", "Mac mini (M4, 2024)"},
    {"Mac16,11", "Mac mini (M4 Pro, 2024)"},
    {"Mac16,12", "MacBook Air (13-inch, M4, 2025)"},
    {"Mac16,13", "MacBook Air (15-inch, M4, 2025)"},
    {"Mac17,2", "MacBook Pro 14-inch (M5)"},
    {"Mac17,3", "MacBook Air (13-inch, M5)"},
    {"Mac17,4", "MacBook Air (15-inch, M5)"},
    {"Mac17,5", "MacBook Neo"},
    {"Mac17,6", "MacBook Pro (16-inch, M5 Max)"},
    {"Mac17,7", "MacBook Pro (14-inch, M5 Max)"},
    {"Mac17,8", "MacBook Pro (16-inch, M5 Pro)"},
    {"Mac17,9", "MacBook Pro (14-inch, M5 Pro)"},
};

// Helper function to safely convert CF types to C strings
static void cf_string_to_cstr(CFTypeRef cf_val, char *buffer, size_t buffer_size) {
    if (!buffer || buffer_size == 0)
        return;

    buffer[0] = '\0';

    // Safety check for null CF reference
    if (!cf_val)
        return;

    // Pre-set the last byte to ensure termination even if conversion fails
    buffer[buffer_size - 1] = '\0';

    if (CFGetTypeID(cf_val) == CFStringGetTypeID()) {
        CFStringRef str_ref = (CFStringRef)cf_val;
        // Use CFStringGetCString with len-1 to ensure space for null terminator
        if (!CFStringGetCString(str_ref, buffer, buffer_size - 1, kCFStringEncodingUTF8))
            buffer[0] = '\0'; // Reset on failure
    }
    else if (CFGetTypeID(cf_val) == CFDataGetTypeID()) {
        CFDataRef data_ref = (CFDataRef)cf_val;
        CFIndex length = CFDataGetLength(data_ref);
        if (length > 0 && length < buffer_size - 1) {
            const UInt8 *bytes = CFDataGetBytePtr(data_ref);
            memcpy(buffer, bytes, length);
            buffer[length] = '\0';
        }
    }

    dmi_clean_field(buffer, buffer_size);
}

// Get a string property from an IOKit registry entry safely
static void get_iokit_string_property(io_registry_entry_t entry, CFStringRef key, char *buffer, size_t buffer_size) {
    // Initialize buffer to empty
    if (!buffer || buffer_size == 0 || !entry || !key) {
        if (buffer && buffer_size > 0)
            buffer[0] = '\0';

        return;
    }

    buffer[0] = '\0';

    // Get the property
    CFTypeRef property = IORegistryEntryCreateCFProperty(entry, key, kCFAllocatorDefault, 0);
    if (property) {
        cf_string_to_cstr(property, buffer, buffer_size);
        CFRelease(property); // Always release the CF object
    }
}

// Get a string property from an IOKit registry entry's parent safely
static void get_parent_iokit_string_property(io_registry_entry_t entry, CFStringRef key,
                                             char *buffer, size_t buffer_size,
                                             const io_name_t plane) {
    // Initialize buffer to empty
    if (!buffer || buffer_size == 0 || !entry || !key || !plane) {
        if (buffer && buffer_size > 0)
            buffer[0] = '\0';

        return;
    }

    buffer[0] = '\0';

    io_registry_entry_t parent;

    // Get parent entry
    kern_return_t result = IORegistryEntryGetParentEntry(entry, plane, &parent);
    if (result == KERN_SUCCESS) {
        get_iokit_string_property(parent, key, buffer, buffer_size);
        IOObjectRelease(parent); // Always release the IO object
    }
}

static bool macos_copy_known_model_name(const char *model_id, char *dst, size_t dst_size) {
    if (!model_id || !*model_id || !dst || !dst_size)
        return false;

    for (size_t i = 0; i < _countof(macos_known_models); i++) {
        if (strcmp(model_id, macos_known_models[i].id) == 0) {
            strcatz(dst, 0, macos_known_models[i].name, dst_size);
            return true;
        }
    }

    return false;
}

static CFPropertyListRef macos_copy_plist(const char *filename) {
    int fd = open(filename, O_RDONLY);
    if (fd == -1)
        return NULL;

    struct stat st;
    if (fstat(fd, &st) == -1 || st.st_size <= 0 || st.st_size > 2 * 1024 * 1024) {
        close(fd);
        return NULL;
    }

    size_t size = (size_t)st.st_size;
    CLEAN_CHAR_P *data = mallocz(size);
    size_t used = 0;

    while (used < size) {
        ssize_t bytes = read(fd, data + used, size - used);
        if (bytes < 0) {
            if (errno == EINTR)
                continue;

            close(fd);
            return NULL;
        }

        if (bytes == 0)
            break;

        used += (size_t)bytes;
    }

    close(fd);

    if (used != size)
        return NULL;

    CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)data, (CFIndex)size);
    if (!cf_data)
        return NULL;

    CFErrorRef error = NULL;
    CFPropertyListRef plist =
        CFPropertyListCreateWithData(kCFAllocatorDefault, cf_data, kCFPropertyListImmutable, NULL, &error);
    CFRelease(cf_data);

    if (error)
        CFRelease(error);

    return plist;
}

static bool macos_copy_plist_marketing_model(const char *model_id, char *dst, size_t dst_size) {
    if (!model_id || !*model_id || !dst || !dst_size)
        return false;

    static const char *const plist_paths[] = {
        "/System/Library/PrivateFrameworks/ServerInformation.framework/Versions/A/Resources/en.lproj/SIMachineAttributes.plist",
        "/System/Library/PrivateFrameworks/ServerInformation.framework/Versions/A/Resources/Base.lproj/SIMachineAttributes.plist",
    };

    for (size_t i = 0; i < _countof(plist_paths); i++) {
        CFPropertyListRef plist = macos_copy_plist(plist_paths[i]);
        if (!plist)
            continue;

        bool found = false;

        if (CFGetTypeID(plist) == CFDictionaryGetTypeID()) {
            CFStringRef model_key = CFStringCreateWithCString(kCFAllocatorDefault, model_id, kCFStringEncodingUTF8);
            if (model_key) {
                CFTypeRef model = CFDictionaryGetValue((CFDictionaryRef)plist, model_key);
                if (model && CFGetTypeID(model) == CFDictionaryGetTypeID()) {
                    CFDictionaryRef model_dict = (CFDictionaryRef)model;
                    CFTypeRef localized = CFDictionaryGetValue(model_dict, CFSTR("_LOCALIZABLE_"));
                    CFDictionaryRef strings =
                        (localized && CFGetTypeID(localized) == CFDictionaryGetTypeID()) ?
                            (CFDictionaryRef)localized : model_dict;

                    CFTypeRef marketing_model = CFDictionaryGetValue(strings, CFSTR("marketingModel"));
                    if (marketing_model && CFGetTypeID(marketing_model) == CFStringGetTypeID()) {
                        cf_string_to_cstr(marketing_model, dst, dst_size);
                        found = dst[0] != '\0';
                    }
                }

                CFRelease(model_key);
            }
        }

        CFRelease(plist);

        if (found)
            return true;
    }

    return false;
}

static bool macos_system_profiler_copy_value(const char *output, const char *key, char *dst, size_t dst_size) {
    const char *line = strstr(output, key);
    if (!line)
        return false;

    const char *value = line + strlen(key);
    while (*value == ' ' || *value == '\t')
        value++;

    const char *end = value;
    while (*end && *end != '\n' && *end != '\r')
        end++;

    snprintfz(dst, dst_size, "%.*s", (int)(end - value), value);
    dmi_clean_field(dst, dst_size);
    return dst[0] != '\0';
}

static bool macos_copy_system_profiler_model_name(const char *model_id, char *dst, size_t dst_size) {
    static const int timeout_ms = 3000;
    static const size_t max_output = 64 * 1024;

    const char *argv[] = {"/usr/sbin/system_profiler", "SPHardwareDataType", NULL};
    POPEN_INSTANCE *pi = spawn_popen_run_argv(argv);
    if (!pi)
        return false;

    int fd = spawn_popen_read_fd(pi);
    if (fd < 0) {
        spawn_popen_kill(pi, 1000);
        return false;
    }

    CLEAN_CHAR_P *output = mallocz(max_output + 1);
    size_t used = 0;
    bool ok = true;
    usec_t stop_ut = now_monotonic_usec() + (usec_t)timeout_ms * USEC_PER_MS;

    while (used < max_output) {
        usec_t now_ut = now_monotonic_usec();
        if (now_ut >= stop_ut) {
            ok = false;
            break;
        }

        int remaining_ms = (int)((stop_ut - now_ut) / USEC_PER_MS);
        if (remaining_ms < 1)
            remaining_ms = 1;
        if (remaining_ms > 250)
            remaining_ms = 250;

        struct pollfd pfd = {
            .fd = fd,
            .events = POLLIN | POLLHUP,
        };

        int rc = poll(&pfd, 1, remaining_ms);
        if (rc < 0) {
            if (errno == EINTR)
                continue;

            ok = false;
            break;
        }

        if (rc == 0)
            continue;

        if (pfd.revents & POLLIN) {
            ssize_t bytes = read(fd, output + used, max_output - used);
            if (bytes < 0) {
                if (errno == EINTR)
                    continue;

                ok = false;
                break;
            }

            if (bytes == 0)
                break;

            used += (size_t)bytes;
            output[used] = '\0';
        }

        if (pfd.revents & POLLHUP)
            break;
    }

    int code = 0;
    SPAWN_TIMEDWAIT_RESULT wait_rc = spawn_popen_timedwait(pi, 250, &code);
    if (wait_rc == SPAWN_TIMEDWAIT_RUNNING || wait_rc == SPAWN_TIMEDWAIT_ERROR) {
        spawn_popen_kill(pi, 1000);
        ok = false;
    }
    else if (code != 0)
        ok = false;

    if (!ok || !used)
        return false;

    char profiler_model_id[64] = "";
    if (macos_system_profiler_copy_value(output, "Model Identifier:", profiler_model_id, sizeof(profiler_model_id)) &&
        model_id && *model_id && strcmp(model_id, profiler_model_id) != 0)
        return false;

    char model_name[64] = "";
    if (!macos_system_profiler_copy_value(output, "Model Name:", model_name, sizeof(model_name)))
        return false;

    if (model_id && *model_id)
        snprintfz(dst, dst_size, "%s (%s)", model_name, model_id);
    else
        strcatz(dst, 0, model_name, dst_size);

    dmi_clean_field(dst, dst_size);
    return dst[0] != '\0';
}

static const char *macos_model_family_from_id(const char *model_id) {
    if (!model_id || !*model_id)
        return "Mac";

    if (strncasecmp(model_id, "MacBookAir", 10) == 0)
        return "MacBook Air";

    if (strncasecmp(model_id, "MacBookPro", 10) == 0)
        return "MacBook Pro";

    if (strncasecmp(model_id, "MacBook", 7) == 0)
        return "MacBook";

    if (strncasecmp(model_id, "Macmini", 7) == 0)
        return "Mac mini";

    if (strncasecmp(model_id, "MacPro", 6) == 0)
        return "Mac Pro";

    if (strncasecmp(model_id, "iMacPro", 7) == 0)
        return "iMac Pro";

    if (strncasecmp(model_id, "iMac", 4) == 0)
        return "iMac";

    if (strncasecmp(model_id, "VirtualMac", 10) == 0)
        return "VirtualMac";

    return "Mac";
}

static void macos_enrich_product_name(DMI_INFO *dmi) {
    if (!dmi || !dmi->product.id[0])
        return;

    if (macos_copy_known_model_name(dmi->product.id, dmi->product.name, sizeof(dmi->product.name)))
        return;

    if (macos_copy_plist_marketing_model(dmi->product.id, dmi->product.name, sizeof(dmi->product.name)))
        return;

    if (macos_copy_system_profiler_model_name(dmi->product.id, dmi->product.name, sizeof(dmi->product.name)))
        return;

    snprintfz(
        dmi->product.name, sizeof(dmi->product.name),
        "%s (%s)", macos_model_family_from_id(dmi->product.id), dmi->product.id);
    dmi_clean_field(dmi->product.name, sizeof(dmi->product.name));
}

static void macos_set_chassis_type(DMI_INFO *dmi) {
    if (!dmi)
        return;

    const char *model_id = dmi->product.id;
    const char *name = dmi->product.name;

    if ((model_id && strncasecmp(model_id, "MacBook", 7) == 0) ||
        (name && strcasestr(name, "MacBook") != NULL))
        safecpy(dmi->chassis.type, "9");
    else if ((model_id && strncasecmp(model_id, "Macmini", 7) == 0) ||
             (name && strcasestr(name, "Mac mini") != NULL))
        safecpy(dmi->chassis.type, "35");
    else if ((model_id && strncasecmp(model_id, "iMac", 4) == 0) ||
             (name && strcasestr(name, "iMac") != NULL))
        safecpy(dmi->chassis.type, "13");
    else if ((model_id && strncasecmp(model_id, "Mac", 3) == 0) ||
             (name && strcasestr(name, "Mac") != NULL)) {
        if (!dmi->chassis.type[0])
            safecpy(dmi->chassis.type, "3");
    }
}

// Get hardware info from IODeviceTree
static void get_devicetree_info(DMI_INFO *dmi) {
    if (!dmi)
        return;

    io_registry_entry_t device_tree = IORegistryEntryFromPath(NETDATA_IOKIT_MAIN_PORT, "IODeviceTree:/");
    if (!device_tree)
        return;

    char model[sizeof(dmi->product.id)] = "";
    get_iokit_string_property(device_tree, CFSTR("model"), model, sizeof(model));
    if (model[0]) {
        if (!dmi->product.id[0])
            safecpy(dmi->product.id, model);

        if (!dmi->product.name[0])
            safecpy(dmi->product.name, model);
    }

    if (!dmi->board.name[0])
        get_iokit_string_property(device_tree, CFSTR("board-id"), dmi->board.name, sizeof(dmi->board.name));

    io_registry_entry_t platform = IORegistryEntryFromPath(NETDATA_IOKIT_MAIN_PORT, "IODeviceTree:/platform");
    if (platform) {
        if (!dmi->sys.vendor[0])
            get_iokit_string_property(platform, CFSTR("manufacturer"), dmi->sys.vendor, sizeof(dmi->sys.vendor));

        IOObjectRelease(platform);
    }

    IOObjectRelease(device_tree);
}

// Get hardware info from IOPlatformExpertDevice
static void get_platform_expert_info(DMI_INFO *dmi) {
    if (!dmi)
        return;

    io_registry_entry_t platform_expert = IORegistryEntryFromPath(
        NETDATA_IOKIT_MAIN_PORT, "IOService:/IOResources/IOPlatformExpertDevice");

    if (!platform_expert)
        return;

    // System vendor - almost always "Apple Inc." for Macs
    get_iokit_string_property(platform_expert, CFSTR("manufacturer"),
                              dmi->sys.vendor, sizeof(dmi->sys.vendor));

    char model[sizeof(dmi->product.id)] = "";
    get_iokit_string_property(platform_expert, CFSTR("model"), model, sizeof(model));
    if (model[0]) {
        safecpy(dmi->product.id, model);
        if (!dmi->product.name[0])
            safecpy(dmi->product.name, model);
    }

    // Model number - can be used as product version
    get_iokit_string_property(platform_expert, CFSTR("model-number"),
                              dmi->product.version, sizeof(dmi->product.version));

    // Board name sometimes available
    get_iokit_string_property(platform_expert, CFSTR("board-id"),
                              dmi->board.name, sizeof(dmi->board.name));

    // System serial number - might be available as IOPlatformSerialNumber
    get_iokit_string_property(platform_expert, CFSTR("IOPlatformSerialNumber"), 
                             dmi->sys.serial, sizeof(dmi->sys.serial));

    // Hardware UUID can be useful to include
    char uuid_str[64] = {0};
    get_iokit_string_property(platform_expert, CFSTR("IOPlatformUUID"), uuid_str, sizeof(uuid_str));
    
    if (uuid_str[0])
        safecpy(dmi->sys.uuid, uuid_str);
        
    // For asset tag, try alternative properties since Apple doesn't provide a specific asset tag property
    // First try chassis tag property if available
    char asset_tag[64] = {0};
    get_iokit_string_property(platform_expert, CFSTR("IOPlatformChassisTag"), asset_tag, sizeof(asset_tag));
    
    // If not available, try using the serial number as an asset tag if not already set
    if (!asset_tag[0]) {
        // Model identifier can be a reasonable alternative for asset tag
        get_iokit_string_property(platform_expert, CFSTR("model"), asset_tag, sizeof(asset_tag));
    }
    
    if (asset_tag[0] && (!dmi->sys.serial[0] || strcmp(asset_tag, dmi->sys.serial) != 0)) {
        safecpy(dmi->sys.asset_tag, asset_tag);
    }

    // Get device type to determine chassis type
    char device_type[64] = {0};
    get_iokit_string_property(platform_expert, CFSTR("device_type"), device_type, sizeof(device_type));

    // Set chassis type based on device_type safely
    if (device_type[0]) {
        if (strcasestr(device_type, "laptop") || strcasestr(device_type, "book"))
            safecpy(dmi->chassis.type, "9");
        else if (strcasestr(device_type, "server"))
            safecpy(dmi->chassis.type, "17");
        else if (strcasestr(device_type, "imac"))
            safecpy(dmi->chassis.type, "13");
        else if (strcasestr(device_type, "mac"))
            safecpy(dmi->chassis.type, "3");
    }

    // If chassis type not set, guess based on product name
    if (!dmi->chassis.type[0] && dmi->product.name[0]) {
        if (strcasestr(dmi->product.name, "book"))
            safecpy(dmi->chassis.type, "9");
        else if (strcasestr(dmi->product.name, "imac"))
            safecpy(dmi->chassis.type, "13");
        else if (strcasestr(dmi->product.name, "mac") && strcasestr(dmi->product.name, "pro"))
            safecpy(dmi->chassis.type, "3");
        else if (strcasestr(dmi->product.name, "mac") && strcasestr(dmi->product.name, "mini"))
            safecpy(dmi->chassis.type, "35");
    }

    IOObjectRelease(platform_expert);
}

// Get SMC revision and system firmware info
static void get_firmware_info(DMI_INFO *dmi) {
    if (!dmi)
        return;

    io_registry_entry_t smc = IOServiceGetMatchingService(
        NETDATA_IOKIT_MAIN_PORT, IOServiceMatching("AppleSMC"));

    if (smc) {
        // SMC revision - can be useful for firmware info
        char smc_version[64] = {0};
        get_iokit_string_property(smc, CFSTR("smc-version"), smc_version, sizeof(smc_version));

        if (smc_version[0]) {
            safecpy(dmi->bios.version, smc_version);
            dmi_clean_field(dmi->bios.version, sizeof(dmi->bios.version));
        }

        IOObjectRelease(smc);
    }

    // Check for BIOS information in IODeviceTree:/rom
    io_registry_entry_t rom = IORegistryEntryFromPath(NETDATA_IOKIT_MAIN_PORT, "IODeviceTree:/rom");
    if (rom) {
        // "version" contains firmware version
        get_iokit_string_property(rom, CFSTR("version"), dmi->bios.version, sizeof(dmi->bios.version));

        // Apple is the vendor for all Mac firmware
        safecpy(dmi->bios.vendor, "Apple");

        // "release-date" can sometimes be found
        get_iokit_string_property(rom, CFSTR("release-date"), dmi->bios.date, sizeof(dmi->bios.date));

        IOObjectRelease(rom);
    }

}

// Get system hardware information using sysctl
static void get_sysctl_info(DMI_INFO *dmi) {
    if (!dmi)
        return;

    if (!dmi->product.id[0]) {
        char model[256] = { 0 };
        size_t len = sizeof(model) - 1;

        if (sysctlbyname("hw.model", model, &len, NULL, 0) == 0) {
            model[len] = '\0';
            safecpy(dmi->product.id, model);
            dmi_clean_field(dmi->product.id, sizeof(dmi->product.id));
        }
    }

    if (!dmi->product.name[0] && dmi->product.id[0])
        safecpy(dmi->product.name, dmi->product.id);
}

// Main function to get hardware info
void os_dmi_info_get(DMI_INFO *dmi) {
    if (!dmi) return;

    // Always set Apple as default vendor
    safecpy(dmi->sys.vendor, "Apple");

    // Get info from IOPlatformExpertDevice
    get_platform_expert_info(dmi);

    // Get info from IODeviceTree
    get_devicetree_info(dmi);

    // Get firmware information
    get_firmware_info(dmi);

    // Get additional info from sysctl
    get_sysctl_info(dmi);

    // Convert the raw model identifier into a human-readable Mac model name when possible.
    macos_enrich_product_name(dmi);

    macos_set_chassis_type(dmi);

    // Set board vendor to match system vendor if not set
    if (!dmi->board.vendor[0] && dmi->sys.vendor[0])
        safecpy(dmi->board.vendor, dmi->sys.vendor);

    // Set chassis vendor to match system vendor if not set
    if (!dmi->chassis.vendor[0] && dmi->sys.vendor[0])
        safecpy(dmi->chassis.vendor, dmi->sys.vendor);

    // Set bios vendor to match system vendor if not set
    if (!dmi->bios.vendor[0] && dmi->sys.vendor[0])
        safecpy(dmi->bios.vendor, dmi->sys.vendor);

    // Default product name if all methods failed
    if (!dmi->product.name[0] && dmi->product.id[0])
        safecpy(dmi->product.name, dmi->product.id);
    else if (!dmi->product.name[0])
        safecpy(dmi->product.name, "Mac");

    // Default chassis type if we couldn't determine it
    if (!dmi->chassis.type[0])
        safecpy(dmi->chassis.type, "3"); // Desktop
        
}

#elif defined(OS_FREEBSD)

#include <sys/types.h>
#include <sys/sysctl.h>
#include <kenv.h>

static void freebsd_get_sysctl_str(const char *name, char *dst, size_t dst_size) {
    size_t len = dst_size - 1; // Reserve space for null terminator
    if (sysctlbyname(name, dst, &len, NULL, 0) == 0 && len < dst_size) {
        dst[len] = '\0';  // Ensure null termination
        dmi_clean_field(dst, dst_size);
    }
    else
        dst[0] = '\0';
}

static void freebsd_get_kenv_str(const char *name, char *dst, size_t dst_size) {
    CLEAN_CHAR_P *tmp = mallocz(dst_size);

    // Preserve any sysctl fallback already collected when the optional kenv value is missing.
    if (kenv(KENV_GET, name, tmp, dst_size - 1) == -1)
        return;

    tmp[dst_size - 1] = '\0';
    dmi_clean_field(tmp, dst_size);
    strcatz(dst, 0, tmp, dst_size);
}

void os_dmi_info_get(DMI_INFO *dmi) {
    if (!dmi) return;
    
    // System information from SMBIOS
    freebsd_get_sysctl_str("hw.vendor", dmi->sys.vendor, sizeof(dmi->sys.vendor));
    freebsd_get_sysctl_str("hw.product", dmi->product.name, sizeof(dmi->product.name));
    freebsd_get_sysctl_str("hw.version", dmi->product.version, sizeof(dmi->product.version));
    freebsd_get_sysctl_str("hw.serial", dmi->sys.serial, sizeof(dmi->sys.serial));

    // Try using kenv for additional information
    freebsd_get_kenv_str("smbios.system.maker", dmi->sys.vendor, sizeof(dmi->sys.vendor));
    freebsd_get_kenv_str("smbios.system.product", dmi->product.name, sizeof(dmi->product.name));
    freebsd_get_kenv_str("smbios.system.version", dmi->product.version, sizeof(dmi->product.version));
    freebsd_get_kenv_str("smbios.system.sku", dmi->product.sku, sizeof(dmi->product.sku));
    freebsd_get_kenv_str("smbios.system.family", dmi->product.family, sizeof(dmi->product.family));
    freebsd_get_kenv_str("smbios.system.serial", dmi->sys.serial, sizeof(dmi->sys.serial));

    // Board information
    freebsd_get_kenv_str("smbios.planar.maker", dmi->board.vendor, sizeof(dmi->board.vendor));
    freebsd_get_kenv_str("smbios.planar.product", dmi->board.name, sizeof(dmi->board.name));
    freebsd_get_kenv_str("smbios.planar.version", dmi->board.version, sizeof(dmi->board.version));
    freebsd_get_kenv_str("smbios.planar.serial", dmi->board.serial, sizeof(dmi->board.serial));

    // BIOS information
    freebsd_get_kenv_str("smbios.bios.vendor", dmi->bios.vendor, sizeof(dmi->bios.vendor));
    freebsd_get_kenv_str("smbios.bios.version", dmi->bios.version, sizeof(dmi->bios.version));
    freebsd_get_kenv_str("smbios.bios.reldate", dmi->bios.date, sizeof(dmi->bios.date));
    freebsd_get_kenv_str("smbios.bios.release", dmi->bios.release, sizeof(dmi->bios.release));

    // Chassis information
    freebsd_get_kenv_str("smbios.chassis.maker", dmi->chassis.vendor, sizeof(dmi->chassis.vendor));
    freebsd_get_kenv_str("smbios.chassis.version", dmi->chassis.version, sizeof(dmi->chassis.version));
    freebsd_get_kenv_str("smbios.chassis.serial", dmi->chassis.serial, sizeof(dmi->chassis.serial));

    // Chassis type
    freebsd_get_kenv_str("smbios.chassis.type", dmi->chassis.type, sizeof(dmi->chassis.type));

    // If we couldn't get system information from SMBIOS, try to use model
    if (!dmi->product.name[0])
        freebsd_get_sysctl_str("hw.model", dmi->product.name, sizeof(dmi->product.name));

    if (dmi->product.name[0])
        safecpy(dmi->product.id, dmi->product.name);
    
    // Try to get asset tags
    freebsd_get_kenv_str("smbios.system.asset_tag", dmi->sys.asset_tag, sizeof(dmi->sys.asset_tag));
    freebsd_get_kenv_str("smbios.chassis.asset_tag", dmi->chassis.asset_tag, sizeof(dmi->chassis.asset_tag));
    freebsd_get_kenv_str("smbios.planar.asset_tag", dmi->board.asset_tag, sizeof(dmi->board.asset_tag));
    
    // Get UUID
    freebsd_get_kenv_str("smbios.system.uuid", dmi->sys.uuid, sizeof(dmi->sys.uuid));
    
}

#elif defined(OS_WINDOWS)

#include <windows.h>

// Helper function to safely read a registry string value
static void windows_read_registry_string(HKEY key_base, const char *subkey_path,
                                         const char *value_name, char *dst, size_t dst_size) {
    HKEY key;
    DWORD type;
    DWORD size = dst_size;

    // Initialize output buffer to empty string
    dst[0] = '\0';

    // Open the registry key
    if (RegOpenKeyExA(key_base, subkey_path, 0, KEY_READ, &key) != ERROR_SUCCESS)
        return;

    // Read the registry value
    if (RegQueryValueExA(key, value_name, NULL, &type, (LPBYTE)dst, &size) == ERROR_SUCCESS) {
        if ((type == REG_SZ || type == REG_EXPAND_SZ || type == REG_MULTI_SZ) && size > 0) {

            if (size >= dst_size)
                size = dst_size - 1;

            dst[size] = '\0';
            dmi_clean_field(dst, dst_size);
        }
    }

    RegCloseKey(key);
}

// SMBIOS structure header definition
typedef struct {
    uint8_t type;
    uint8_t length;
    uint16_t handle;
    // Remaining fields are variable
} smbios_header_t;

// SMBIOS data container
typedef struct {
    BYTE *data;           // The raw SMBIOS data buffer
    DWORD size;           // Size of the data buffer
    DWORD entries_count;  // Number of valid structure entries found
    bool valid;           // Whether the data is valid
} smbios_data_t;

// Helper to safely parse SMBIOS strings with improved bounds checking
static char *get_smbios_string(const BYTE *table_start, DWORD table_size, 
                             const char *string_start, uint8_t index, 
                             char *buffer, size_t buffer_size) {
    if (!string_start || !buffer || buffer_size == 0 || index == 0) {
        if (buffer && buffer_size > 0)
            buffer[0] = '\0';
        return NULL;
    }
    
    buffer[0] = '\0';
    
    // Check if string_start is within bounds of the table
    if (string_start < (const char*)table_start || 
        string_start >= (const char*)(table_start + table_size)) {
        return NULL;
    }
    
    // Navigate to the indexed string
    const char *s = string_start;
    const char *end = (const char*)(table_start + table_size);
    uint8_t current_index = 1;
    
    // Set a reasonable limit to prevent infinite loops with corrupted data
    const int MAX_ITERATIONS = 100;
    int iterations = 0;
    
    while (current_index < index && s < end && iterations < MAX_ITERATIONS) {
        // Skip to end of current string
        while (s < end && *s != '\0')
            s++;
            
        // Skip past terminating null
        if (s < end)
            s++;
            
        // If we hit the end of strings section (double null) or table boundary
        if (s >= end || *s == '\0')
            return NULL;
            
        current_index++;
        iterations++;
    }
    
    // If we found our string
    if (current_index == index && s < end && *s != '\0') {
        // Copy safely with explicit bounds checking
        size_t i = 0;
        while (s < end && *s != '\0' && i < buffer_size - 1) {
            buffer[i++] = *s++;
        }
        buffer[i] = '\0';
        
        dmi_clean_field(buffer, buffer_size);
        return buffer;
    }
    
    return NULL;
}

// Get SMBIOS data with proper memory management
static smbios_data_t get_smbios_data(void) {
    smbios_data_t result = {NULL, 0, 0, false};
    
    // Request SMBIOS data size
    DWORD size = GetSystemFirmwareTable('RSMB', 0, NULL, 0);
    if (size == 0 || size > 1024*1024) // Sanity check on size
        return result;
        
    // Allocate memory with zero initialization
    result.data = (BYTE *)mallocz(size);
    if (!result.data)
        return result;
        
    result.size = size;
    
    // Get the SMBIOS data
    DWORD bytes_read = GetSystemFirmwareTable('RSMB', 0, result.data, result.size);
    if (bytes_read == 0 || bytes_read > result.size) {
        freez(result.data);
        result.data = NULL;
        result.size = 0;
        return result;
    }
    
    result.valid = true;
    return result;
}

// Process BIOS Information (Type 0)
static void process_smbios_bios_info(const smbios_header_t *header,
                                  DMI_INFO *dmi,
                                  const char *string_table,
                                  const BYTE *smbios_data,
                                  DWORD smbios_size) {
    if (header->length < 18 || !dmi) // Minimum size for BIOS info
        return;
        
    const BYTE *data = (const BYTE *)header;
    char temp_str[256];
    
    // BIOS Vendor (string index at offset 4)
    if (data[4] > 0 && get_smbios_string(smbios_data, smbios_size, string_table, 
                                     data[4], temp_str, sizeof(temp_str))) {
        safecpy(dmi->bios.vendor, temp_str);
    }
    
    // BIOS Version (string index at offset 5)
    if (data[5] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
                                     data[5], temp_str, sizeof(temp_str))) {
        safecpy(dmi->bios.version, temp_str);
    }
    
    // BIOS Release Date (string index at offset 8)
    if (data[8] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
                                     data[8], temp_str, sizeof(temp_str))) {
        safecpy(dmi->bios.date, temp_str);
    }
}

// Process System Information (Type 1)
static void process_smbios_system_info(const smbios_header_t *header,
                                    DMI_INFO *dmi,
                                    const char *string_table,
                                    const BYTE *smbios_data,
                                    DWORD smbios_size) {
    if (header->length < 8 || !dmi) // Minimum size for System info
        return;
        
    const BYTE *data = (const BYTE *)header;
    char temp_str[256];
    
    // Manufacturer (string index at offset 4)
    if (data[4] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
                                     data[4], temp_str, sizeof(temp_str))) {
        safecpy(dmi->sys.vendor, temp_str);
    }
    
    // Product Name (string index at offset 5)
    if (data[5] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
                                     data[5], temp_str, sizeof(temp_str))) {
        safecpy(dmi->product.id, temp_str);
        safecpy(dmi->product.name, temp_str);
    }
    
    // Version (string index at offset 6)
    if (data[6] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
                                     data[6], temp_str, sizeof(temp_str))) {
        safecpy(dmi->product.version, temp_str);
    }
    
    // Serial Number (string index at offset 7)
    if (data[7] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
                                     data[7], temp_str, sizeof(temp_str))) {
        safecpy(dmi->sys.serial, temp_str);
    }
    
    // If structure is long enough for family (SMBIOS 2.1+)
    if (header->length >= 25 && data[21] > 0 && 
        get_smbios_string(smbios_data, smbios_size, string_table,
                       data[21], temp_str, sizeof(temp_str))) {
        safecpy(dmi->product.family, temp_str);
    }
    
    // Extract system UUID (16 bytes starting at offset 8)
    if (header->length >= 24) {
        // Verify we have enough data to access all bytes safely
        if ((uintptr_t)data + 23 < (uintptr_t)smbios_data + smbios_size) {
            // UUID is stored as 16 bytes, we'll format it as a standard UUID string
            char uuid_str[40] = {0}; // 36 chars for UUID + null terminator
            
            // Note: SMBIOS UUID needs byte swapping for first three fields
            int ret = snprintf(uuid_str, sizeof(uuid_str),
                     "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
                     data[11], data[10], data[9], data[8],         // field 1 (byte swapped)
                     data[13], data[12],                           // field 2 (byte swapped)
                     data[15], data[14],                           // field 3 (byte swapped)
                     data[16], data[17],                           // field 4 (not swapped)
                     data[18], data[19], data[20], data[21], data[22], data[23]); // field 5 (not swapped)
            
            // Verify the formatting worked and buffer wasn't truncated
            if (ret > 0 && ret < (int)sizeof(uuid_str)) {
                // Only set if not all zeros (some systems report all zeros)
                if (uuid_str[0] != '0' || uuid_str[1] != '0' || uuid_str[2] != '0' || uuid_str[3] != '0') {
                    safecpy(dmi->sys.uuid, uuid_str);
                }
            }
        }
    }
    
    // Asset Tag is sometimes available in newer SMBIOS versions
    if (header->length >= 27 && data[26] > 0 &&
        get_smbios_string(smbios_data, smbios_size, string_table,
                       data[26], temp_str, sizeof(temp_str))) {
        safecpy(dmi->sys.asset_tag, temp_str);
    }
}

// Process Baseboard Information (Type 2)
static void process_smbios_baseboard_info(const smbios_header_t *header,
                                       DMI_INFO *dmi,
                                       const char *string_table,
                                       const BYTE *smbios_data,
                                       DWORD smbios_size) {
    if (header->length < 8 || !dmi) // Minimum size for Baseboard info
        return;
        
    const BYTE *data = (const BYTE *)header;
    char temp_str[256];
    
    // Manufacturer (string index at offset 4)
    if (data[4] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
                                     data[4], temp_str, sizeof(temp_str))) {
        safecpy(dmi->board.vendor, temp_str);
    }
    
    // Product (string index at offset 5)
    if (data[5] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
                                     data[5], temp_str, sizeof(temp_str))) {
        safecpy(dmi->board.name, temp_str);
    }
    
    // Version (string index at offset 6)
    if (data[6] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
                                     data[6], temp_str, sizeof(temp_str))) {
        safecpy(dmi->board.version, temp_str);
    }
    
    // Serial Number (string index at offset 7)
    if (data[7] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
                                     data[7], temp_str, sizeof(temp_str))) {
        safecpy(dmi->board.serial, temp_str);
    }
    
    // Asset Tag (string index at offset 8)
    if (header->length >= 9 && data[8] > 0 &&
        get_smbios_string(smbios_data, smbios_size, string_table,
                      data[8], temp_str, sizeof(temp_str))) {
        safecpy(dmi->board.asset_tag, temp_str);
    }
}

// Process Chassis Information (Type 3)
static void process_smbios_chassis_info(const smbios_header_t *header,
                                     DMI_INFO *dmi,
                                     const char *string_table,
                                     const BYTE *smbios_data,
                                     DWORD smbios_size) {
    if (header->length < 9 || !dmi) // Minimum size for Chassis info
        return;
        
    const BYTE *data = (const BYTE *)header;
    char temp_str[256];
    
    // Manufacturer (string index at offset 4)
    if (data[4] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
                                     data[4], temp_str, sizeof(temp_str))) {
        safecpy(dmi->chassis.vendor, temp_str);
    }
    
    // Type (numerical value at offset 5)
    BYTE chassis_type = data[5] & 0x7F; // Mask out MSB
    snprintf(dmi->chassis.type, sizeof(dmi->chassis.type), "%d", chassis_type);
    
    // Version (string index at offset 6)
    if (data[6] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
                                     data[6], temp_str, sizeof(temp_str))) {
        safecpy(dmi->chassis.version, temp_str);
    }
    
    // Serial Number (string index at offset 7)
    if (data[7] > 0 && get_smbios_string(smbios_data, smbios_size, string_table,
                                     data[7], temp_str, sizeof(temp_str))) {
        safecpy(dmi->chassis.serial, temp_str);
    }
    
    // Asset Tag (string index at offset 8)
    if (header->length >= 9 && data[8] > 0 &&
        get_smbios_string(smbios_data, smbios_size, string_table, 
                      data[8], temp_str, sizeof(temp_str))) {
        safecpy(dmi->chassis.asset_tag, temp_str);
    }
}

// Process a complete SMBIOS structure
static void process_smbios_structure(const smbios_header_t *header, 
                                  DMI_INFO *dmi,
                                  const char *string_table,
                                  const BYTE *smbios_data,
                                  DWORD smbios_size) {
    if (!dmi) return;
    
    switch (header->type) {
        case 0: // BIOS Information
            process_smbios_bios_info(header, dmi, string_table, smbios_data, smbios_size);
            break;
            
        case 1: // System Information
            process_smbios_system_info(header, dmi, string_table, smbios_data, smbios_size);
            break;
            
        case 2: // Baseboard Information
            process_smbios_baseboard_info(header, dmi, string_table, smbios_data, smbios_size);
            break;
            
        case 3: // Chassis Information
            process_smbios_chassis_info(header, dmi, string_table, smbios_data, smbios_size);
            break;
    }
}

// Parse all SMBIOS structures with robust error handling
static void parse_smbios_structures(const smbios_data_t smbios, DMI_INFO *dmi) {
    if (!smbios.valid || !smbios.data || smbios.size < 8 || !dmi)
        return;
        
    // The SMBIOS header is at offset 8
    const BYTE *current = smbios.data + 8;
    const BYTE *end = smbios.data + smbios.size;
    
    // Track already visited types to avoid duplicates in corrupted tables
    uint8_t visited[256] = {0};
    int structures_parsed = 0;
    
    // Temporary buffer for string parsing
    char temp_str[256];
    
    while (current + sizeof(smbios_header_t) <= end) {
        const smbios_header_t *header = (const smbios_header_t *)current;
        
        // Basic sanity checks
        if (header->length < sizeof(smbios_header_t) || current + header->length > end) {
            break; // Invalid structure
        }
        
        // If we've already seen this type and want to skip duplicates
        if (visited[header->type]) {
            // Find the string terminator (double NULL)
            const char *strings = (const char *)(current + header->length);
            const char *str_end = strings;
            bool found_terminator = false;
            
            // Set a reasonable limit to prevent infinite loops
            const int MAX_STRING_SEARCH = 1000;
            int search_count = 0;
            
            // Search with explicit bounds check for string terminator
            while (str_end + 1 < (const char *)end && !found_terminator && search_count < MAX_STRING_SEARCH) {
                if (str_end[0] == 0 && str_end[1] == 0) {
                    found_terminator = true;
                    break;
                }
                str_end++;
                search_count++;
            }
            
            if (found_terminator) {
                // Advance to next structure
                current = (const BYTE *)(str_end + 2);
                continue;
            } else {
                break; // Corrupt data
            }
        }
        
        // Mark this type as processed
        visited[header->type] = 1;
        structures_parsed++;
        
        // Process the structure based on type
        const char *string_table = (const char *)(current + header->length);
        if (string_table < (const char *)end) {
            process_smbios_structure(header, dmi, string_table, smbios.data, smbios.size);
        }
        
        // Find string table end (double null terminator)
        const char *str_end = string_table;
        bool found_terminator = false;
        
        // Set a reasonable limit to prevent infinite loops
        const int MAX_STRING_SEARCH = 1000;
        int search_count = 0;
        
        // Search for end of strings with explicit bounds check
        const char *end_char = (const char *)end;
        while (str_end + 1 < end_char && !found_terminator && search_count < MAX_STRING_SEARCH) {
            if (str_end[0] == 0 && str_end[1] == 0) {
                found_terminator = true;
                break;
            }
            str_end++;
            search_count++;
        }
        
        if (!found_terminator) {
            break; // Corrupt data
        }
        
        // Move to the next structure
        current = (const BYTE *)(str_end + 2);
        
        // Check for end marker or out of bounds
        if (current >= end || *current == 127)
            break;
    }
}
static void windows_get_smbios_info(DMI_INFO *dmi) {
    if (!dmi) return;
    
    // Get SMBIOS data using our improved container structure
    smbios_data_t smbios = get_smbios_data();
    if (!smbios.valid)
        return;
        
    // Process the SMBIOS data with our improved parser
    parse_smbios_structures(smbios, dmi);
    
    // Clean up
    freez(smbios.data);
}

// Fallback method using registry
static void windows_get_registry_info(DMI_INFO *dmi) {
    if (!dmi) return;
    
    // System manufacturer and model from registry
    windows_read_registry_string(
        HKEY_LOCAL_MACHINE,
        "HARDWARE\\DESCRIPTION\\System\\BIOS",
        "SystemManufacturer",
        dmi->sys.vendor,
        sizeof(dmi->sys.vendor)
    );

    {
        char product_name[sizeof(dmi->product.name)] = "";
        windows_read_registry_string(
            HKEY_LOCAL_MACHINE,
            "HARDWARE\\DESCRIPTION\\System\\BIOS",
            "SystemProductName",
            product_name,
            sizeof(product_name)
        );

        if (product_name[0]) {
            if (!dmi->product.id[0])
                safecpy(dmi->product.id, product_name);

            safecpy(dmi->product.name, product_name);
        }
    }
    
    // System Serial Number
    windows_read_registry_string(
        HKEY_LOCAL_MACHINE,
        "HARDWARE\\DESCRIPTION\\System\\BIOS",
        "SystemSerialNumber",
        dmi->sys.serial,
        sizeof(dmi->sys.serial)
    );

    // BIOS information
    windows_read_registry_string(
        HKEY_LOCAL_MACHINE,
        "HARDWARE\\DESCRIPTION\\System\\BIOS",
        "BIOSVendor",
        dmi->bios.vendor,
        sizeof(dmi->bios.vendor)
    );

    windows_read_registry_string(
        HKEY_LOCAL_MACHINE,
        "HARDWARE\\DESCRIPTION\\System\\BIOS",
        "BIOSVersion",
        dmi->bios.version,
        sizeof(dmi->bios.version)
    );

    windows_read_registry_string(
        HKEY_LOCAL_MACHINE,
        "HARDWARE\\DESCRIPTION\\System\\BIOS",
        "BIOSReleaseDate",
        dmi->bios.date,
        sizeof(dmi->bios.date)
    );

    // Board information
    windows_read_registry_string(
        HKEY_LOCAL_MACHINE,
        "HARDWARE\\DESCRIPTION\\System\\BIOS",
        "BaseBoardManufacturer",
        dmi->board.vendor,
        sizeof(dmi->board.vendor)
    );

    windows_read_registry_string(
        HKEY_LOCAL_MACHINE,
        "HARDWARE\\DESCRIPTION\\System\\BIOS",
        "BaseBoardProduct",
        dmi->board.name,
        sizeof(dmi->board.name)
    );

    windows_read_registry_string(
        HKEY_LOCAL_MACHINE,
        "HARDWARE\\DESCRIPTION\\System\\BIOS",
        "BaseBoardVersion",
        dmi->board.version,
        sizeof(dmi->board.version)
    );
    
    // Base Board Serial
    windows_read_registry_string(
        HKEY_LOCAL_MACHINE,
        "HARDWARE\\DESCRIPTION\\System\\BIOS",
        "BaseBoardSerialNumber",
        dmi->board.serial,
        sizeof(dmi->board.serial)
    );
    
    // Chassis Serial (might not be available in registry, but try anyway)
    windows_read_registry_string(
        HKEY_LOCAL_MACHINE,
        "HARDWARE\\DESCRIPTION\\System\\BIOS",
        "ChassisSerialNumber",
        dmi->chassis.serial,
        sizeof(dmi->chassis.serial)
    );
    
}

// Main function to get hardware information
void os_dmi_info_get(DMI_INFO *dmi) {
    if (!dmi) return;
    
    // First try SMBIOS data through firmware table API
    windows_get_smbios_info(dmi);

    // Try registry as a fallback or to fill missing values
    windows_get_registry_info(dmi);

    // Get asset tags if not set by SMBIOS
    if (!dmi->sys.asset_tag[0]) {
        windows_read_registry_string(
            HKEY_LOCAL_MACHINE,
            "HARDWARE\\DESCRIPTION\\System\\BIOS",
            "SystemAssetTag",
            dmi->sys.asset_tag,
            sizeof(dmi->sys.asset_tag)
        );
    }
    
    if (!dmi->board.asset_tag[0]) {
        windows_read_registry_string(
            HKEY_LOCAL_MACHINE,
            "HARDWARE\\DESCRIPTION\\System\\BIOS",
            "BaseBoardAssetTag",
            dmi->board.asset_tag,
            sizeof(dmi->board.asset_tag)
        );
    }
    
    if (!dmi->chassis.asset_tag[0]) {
        windows_read_registry_string(
            HKEY_LOCAL_MACHINE,
            "HARDWARE\\DESCRIPTION\\System\\BIOS",
            "ChassisAssetTag",
            dmi->chassis.asset_tag,
            sizeof(dmi->chassis.asset_tag)
        );
    }
    

    // If chassis type is not set or not a valid number, set a default
    if (!dmi->chassis.type[0] || atoi(dmi->chassis.type) <= 0) {
        // Check common system names for laptops
        if (strcasestr(dmi->product.name, "notebook") != NULL ||
            strcasestr(dmi->product.name, "laptop") != NULL ||
            strcasestr(dmi->product.name, "book") != NULL) {
            safecpy(dmi->chassis.type, "9");  // Laptop
        }
        // Check for servers
        else if (strcasestr(dmi->product.name, "server") != NULL) {
            safecpy(dmi->chassis.type, "17");  // Server
        }
        // Default to desktop
        else {
            safecpy(dmi->chassis.type, "3");  // Desktop
        }
    }
}

#else
void os_dmi_info_get(DMI_INFO *dmi) {
    // No implementation for this platform
}
#endif

// --------------------------------------------------------------------------------------------------------------------
// public API

void dmi_info_init(DMI_INFO *dmi) {
    if (!dmi) return;
    
    // System information
    dmi->sys.vendor[0] = '\0';
    dmi->sys.serial[0] = '\0';
    dmi->sys.uuid[0] = '\0';
    dmi->sys.asset_tag[0] = '\0';
    
    // Product information
    dmi->product.id[0] = '\0';
    dmi->product.name[0] = '\0';
    dmi->product.version[0] = '\0';
    dmi->product.sku[0] = '\0';
    dmi->product.family[0] = '\0';
    
    // Board information
    dmi->board.vendor[0] = '\0';
    dmi->board.name[0] = '\0';
    dmi->board.version[0] = '\0';
    dmi->board.serial[0] = '\0';
    dmi->board.asset_tag[0] = '\0';
    
    // BIOS information
    dmi->bios.vendor[0] = '\0';
    dmi->bios.version[0] = '\0';
    dmi->bios.date[0] = '\0';
    dmi->bios.release[0] = '\0';
    
    // Chassis information
    dmi->chassis.vendor[0] = '\0';
    dmi->chassis.version[0] = '\0';
    dmi->chassis.type[0] = '\0';
    dmi->chassis.serial[0] = '\0';
    dmi->chassis.asset_tag[0] = '\0';
}
