diff --git a/inc/config.h b/inc/config.h index 381df22..709a800 100644 --- a/inc/config.h +++ b/inc/config.h @@ -1,8 +1,8 @@ #ifndef CONFIG_H #define CONFIG_H -#define WIN32_LEAN_AND_MEAN #include +#include "ini.h" #define FILE_EXISTS(a) (GetFileAttributes(a) != INVALID_FILE_ATTRIBUTES) @@ -15,6 +15,7 @@ typedef struct CNCDDRAWCONFIG char game_path[MAX_PATH]; char process_file_name[MAX_PATH]; char process_file_ext[MAX_PATH]; + INIFILE ini; /* Optional settings */ diff --git a/inc/ini.h b/inc/ini.h index 9b73604..ee88575 100644 --- a/inc/ini.h +++ b/inc/ini.h @@ -1,6 +1,20 @@ #ifndef INI_H #define INI_H -BOOL ini_section_exists(char* section); +typedef struct +{ + char filename[MAX_PATH]; + + struct { + unsigned long hash; + char* data; + }*sections; +} INIFILE; + +void ini_create(INIFILE* ini, char* filename); +DWORD ini_get_string(INIFILE* ini, LPCSTR section, LPCSTR key, LPCSTR def, LPSTR buf, DWORD size); +BOOL ini_get_bool(INIFILE* ini, LPCSTR section, LPCSTR key, BOOL def); +int ini_get_int(INIFILE* ini, LPCSTR section, LPCSTR key, int def); +void ini_free(INIFILE* ini); #endif diff --git a/src/config.c b/src/config.c index 55b0e0a..a96644c 100644 --- a/src/config.c +++ b/src/config.c @@ -106,6 +106,8 @@ void cfg_load() GET_BOOL(g_config.mgs_hack, "mgs_hack", FALSE); GameHandlesClose = GameHandlesClose || g_config.infantryhack; + + ini_free(&g_config.ini); } void cfg_save() @@ -1098,31 +1100,25 @@ static void cfg_init() { cfg_create_ini(); } + + ini_create(&g_config.ini, g_config.ini_path); } static DWORD cfg_get_string(LPCSTR key, LPCSTR default_value, LPSTR out_string, DWORD out_size) { - if (!g_config.ini_path[0]) - cfg_init(); - char buf[MAX_PATH] = { 0 }; - if (ini_section_exists(g_config.process_file_name)) - { - DWORD s = GetPrivateProfileStringA( - g_config.process_file_name, key, "", out_string, out_size, g_config.ini_path); + DWORD s = ini_get_string(&g_config.ini, g_config.process_file_name, key, "", out_string, out_size); - if (s > 0) + if (s > 0) + { + if (ini_get_string(&g_config.ini, g_config.process_file_name, "checkfile", "", buf, sizeof(buf)) > 0) { - if (GetPrivateProfileStringA( - g_config.process_file_name, "checkfile", "", buf, sizeof(buf), g_config.ini_path) > 0) - { - if (FILE_EXISTS(buf)) - return s; - } - else + if (FILE_EXISTS(buf)) return s; } + else + return s; } for (int i = 2; i < 10; i++) @@ -1130,22 +1126,19 @@ static DWORD cfg_get_string(LPCSTR key, LPCSTR default_value, LPSTR out_string, char section[MAX_PATH] = { 0 }; _snprintf(section, sizeof(section) - 1, "%s/%d", g_config.process_file_name, i); - if (ini_section_exists(section)) - { - DWORD s = GetPrivateProfileStringA(section, key, "", out_string, out_size, g_config.ini_path); + DWORD s = ini_get_string(&g_config.ini, section, key, "", out_string, out_size); - if (s > 0) + if (s > 0) + { + if (ini_get_string(&g_config.ini, section, "checkfile", "", buf, sizeof(buf)) > 0) { - if (GetPrivateProfileStringA(section, "checkfile", "", buf, sizeof(buf), g_config.ini_path) > 0) - { - if (FILE_EXISTS(buf)) - return s; - } + if (FILE_EXISTS(buf)) + return s; } } } - return GetPrivateProfileStringA("ddraw", key, default_value, out_string, out_size, g_config.ini_path); + return ini_get_string(&g_config.ini, "ddraw", key, default_value, out_string, out_size); } static BOOL cfg_get_bool(LPCSTR key, BOOL default_value) diff --git a/src/ini.c b/src/ini.c index 38c42bc..69456b5 100644 --- a/src/ini.c +++ b/src/ini.c @@ -1,49 +1,173 @@ #include +#include #include "debug.h" #include "config.h" #include "crc32.h" +#include "ini.h" -static unsigned long g_ini_section_hashes[1024]; +// Microsoft: The maximum profile section size is 32,767 characters. +#define BUF_SIZE (8192) -BOOL ini_section_exists(char* section) +void ini_create(INIFILE* ini, char* filename) { - if (!g_ini_section_hashes[0]) - { - char* buf = calloc(8192, 1); - if (buf) - { - if (GetPrivateProfileSectionNamesA(buf, 8192, g_config.ini_path) > 0) - { - for (int i = 0; *buf && i < sizeof(g_ini_section_hashes) / sizeof(g_ini_section_hashes[0]); i++) - { - size_t len = strlen(buf); + if (!ini || !filename || !filename[0]) + return; - for (char* p = buf; *p; ++p) + ini->sections = calloc(sizeof(ini->sections[0]), 1); + if (ini->sections) + { + strncpy(ini->filename, filename, sizeof(ini->filename) - 1); + + char* names = calloc(BUF_SIZE, 1); + if (names) + { + if (GetPrivateProfileSectionNamesA(names, BUF_SIZE, filename) > 0) + { + char* name = names; + + for (int i = 0; *name; i++) + { + ini->sections = realloc(ini->sections, sizeof(ini->sections[0]) * (i + 2)); + + if (!ini->sections) + return; + + memset(&ini->sections[i + 1], 0, sizeof(ini->sections[0])); + + char* buf = malloc(BUF_SIZE); + if (buf) + { + DWORD size = GetPrivateProfileSectionA(name, buf, BUF_SIZE, ini->filename); + if (size > 0) + { + ini->sections[i].data = malloc(size + 2); + if (ini->sections[i].data) + { + memcpy(ini->sections[i].data, buf, size + 2); + } + } + + free(buf); + } + + size_t len = strlen(name); + + for (char* p = name; *p; ++p) *p = tolower(*p); - g_ini_section_hashes[i] = Crc32_ComputeBuf(0, buf, len); + ini->sections[i].hash = Crc32_ComputeBuf(0, name, len); - buf += len + 1; + name += len + 1; } } - - free(buf); + + free(names); } } +} + +DWORD ini_get_string(INIFILE* ini, LPCSTR section, LPCSTR key, LPCSTR def, LPSTR buf, DWORD size) +{ + if (!buf || size == 0) + { + return 0; + } + + if (!ini || !ini->sections || !section || !key) + { + goto end; + } + + size_t key_len = strlen(key); + + if (key_len == 0 || strlen(section) == 0) + { + goto end; + } char s[MAX_PATH]; strncpy(s, section, sizeof(s) - 1); + buf[sizeof(s) - 1] = 0; for (char* p = s; *p; ++p) *p = tolower(*p); - + unsigned long hash = Crc32_ComputeBuf(0, s, strlen(s)); - - for (int i = 0; i < sizeof(g_ini_section_hashes) / sizeof(g_ini_section_hashes[0]) && g_ini_section_hashes[i]; i++) + + for (int i = 0; ini->sections[i].hash; i++) { - if (g_ini_section_hashes[i] == hash) - return TRUE; + if (ini->sections[i].hash == hash) + { + if (!ini->sections[i].data) + break; + + for (char* p = ini->sections[i].data; *p; p += strlen(p) + 1) + { + if (_strnicmp(key, p, key_len) == 0 && p[key_len] == '=') + { + strncpy(buf, &p[key_len + 1], size - 1); + buf[size - 1] = 0; + return strlen(buf); + } + } + + break; + } } - return FALSE; +end: + if (def) + { + strncpy(buf, def, size - 1); + buf[size - 1] = 0; + return strlen(buf); + } + + buf[0] = 0; + + return 0; +} + +BOOL ini_get_bool(INIFILE* ini, LPCSTR section, LPCSTR key, BOOL def) +{ + char value[8]; + ini_get_string(ini, section, key, def ? "Yes" : "No", value, sizeof(value)); + + return (_stricmp(value, "yes") == 0 || _stricmp(value, "true") == 0 || _stricmp(value, "1") == 0); +} + +int ini_get_int(INIFILE* ini, LPCSTR section, LPCSTR key, int def) +{ + char def_str[32]; + _snprintf(def_str, sizeof(def_str) - 1, "%d", def); + + char value[32]; + ini_get_string(ini, section, key, def_str, value, sizeof(value)); + + if (strstr(value, "0x")) + { + return strtol(value, NULL, 0); + } + else + { + return atoi(value); + } +} + +void ini_free(INIFILE* ini) +{ + if (ini->sections) + { + for (int i = 0; ini->sections[i].hash; i++) + { + if (ini->sections[i].data) + { + free(ini->sections[i].data); + ini->sections[i].data = NULL; + } + } + + free(ini->sections); + ini->sections = NULL; + } }