mirror of
https://github.com/CrazyRedMachine/popnhax.git
synced 2024-11-23 22:00:57 +01:00
config file advanced diagnostics
This commit is contained in:
parent
4c92b4fda7
commit
c775320a07
@ -3,6 +3,7 @@
|
||||
|
||||
#include "util/crc32.h"
|
||||
#include "util/log.h"
|
||||
#include "util/psmap.h"
|
||||
#include "config.h"
|
||||
|
||||
#define F_OK 0
|
||||
@ -220,6 +221,272 @@ static bool config_make_opt(const char *xml_filename){
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool type_to_str(enum psmap_property_type type, char* expected_type)
|
||||
{
|
||||
bool res = true;
|
||||
switch (type)
|
||||
{
|
||||
case PSMAP_PROPERTY_TYPE_S8:
|
||||
strcpy(expected_type, "s8");
|
||||
break;
|
||||
case PSMAP_PROPERTY_TYPE_U8:
|
||||
strcpy(expected_type, "u8");
|
||||
break;
|
||||
case PSMAP_PROPERTY_TYPE_S16:
|
||||
strcpy(expected_type, "s16");
|
||||
break;
|
||||
case PSMAP_PROPERTY_TYPE_U16:
|
||||
strcpy(expected_type, "u16");
|
||||
break;
|
||||
case PSMAP_PROPERTY_TYPE_S32:
|
||||
strcpy(expected_type, "s32");
|
||||
break;
|
||||
case PSMAP_PROPERTY_TYPE_U32:
|
||||
strcpy(expected_type, "u32");
|
||||
break;
|
||||
case PSMAP_PROPERTY_TYPE_S64:
|
||||
strcpy(expected_type, "s64");
|
||||
break;
|
||||
case PSMAP_PROPERTY_TYPE_U64:
|
||||
strcpy(expected_type, "u64");
|
||||
break;
|
||||
case PSMAP_PROPERTY_TYPE_STR:
|
||||
strcpy(expected_type, "str");
|
||||
break;
|
||||
case PSMAP_PROPERTY_TYPE_FLOAT:
|
||||
strcpy(expected_type, "float");
|
||||
break;
|
||||
case PSMAP_PROPERTY_TYPE_ATTR:
|
||||
strcpy(expected_type, "attr");
|
||||
break;
|
||||
case PSMAP_PROPERTY_TYPE_BOOL:
|
||||
strcpy(expected_type, "bool");
|
||||
break;
|
||||
default:
|
||||
strcpy(expected_type, "INVALID");
|
||||
res = false;
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int64_t get_min(enum psmap_property_type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PSMAP_PROPERTY_TYPE_S8:
|
||||
return -128;
|
||||
case PSMAP_PROPERTY_TYPE_S16:
|
||||
return -32768;
|
||||
case PSMAP_PROPERTY_TYPE_S32:
|
||||
return -2147483648;
|
||||
case PSMAP_PROPERTY_TYPE_S64:
|
||||
return LLONG_MIN;
|
||||
case PSMAP_PROPERTY_TYPE_U8:
|
||||
case PSMAP_PROPERTY_TYPE_U16:
|
||||
case PSMAP_PROPERTY_TYPE_U32:
|
||||
case PSMAP_PROPERTY_TYPE_U64:
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
static int64_t get_max(enum psmap_property_type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PSMAP_PROPERTY_TYPE_S8:
|
||||
return 127;
|
||||
case PSMAP_PROPERTY_TYPE_S16:
|
||||
return 32767;
|
||||
case PSMAP_PROPERTY_TYPE_S32:
|
||||
return 2147483647;
|
||||
case PSMAP_PROPERTY_TYPE_S64:
|
||||
return 9223372036854775807;
|
||||
case PSMAP_PROPERTY_TYPE_U8:
|
||||
return 255;
|
||||
case PSMAP_PROPERTY_TYPE_U16:
|
||||
return 65535;
|
||||
case PSMAP_PROPERTY_TYPE_U32:
|
||||
return 4294967295;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_valid(const char *option_line, uint8_t type, uint32_t member_width, char **reason)
|
||||
{
|
||||
char tmp_reason[256] = {0};
|
||||
char open[64] = {0};
|
||||
char expected_type[8] = {0};
|
||||
char option_type[64] = {0};
|
||||
char value[64] = {0};
|
||||
char close[64] = {0};
|
||||
if (!type_to_str((enum psmap_property_type) type, expected_type))
|
||||
{
|
||||
sprintf(tmp_reason, "bad type value"); // shouldn't happen as it's psmap struct type
|
||||
*reason = strdup(tmp_reason);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* attempt to scan line */
|
||||
int num = sscanf(option_line, " %s __type=\"%[^<>\"]\">%[^><\"]%[^\"\r\n] ", open, option_type, value, close);
|
||||
if ( num == 2 && strcmp(option_type, "str")==0 )
|
||||
{
|
||||
num = sscanf(option_line, " %s __type=\"%[^<>\"]\">%[^\"\r\n] ", open, option_type, close);
|
||||
if (num != 3)
|
||||
{
|
||||
sprintf(tmp_reason, "malformed line (should be <option_name __type=\"option_type\">option_value</option_name>)");
|
||||
*reason = strdup(tmp_reason);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( num != 4 )
|
||||
{
|
||||
sprintf(tmp_reason, "malformed line (should be <option_name __type=\"option_type\">option_value</option_name>)");
|
||||
*reason = strdup(tmp_reason);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* tag errors */
|
||||
if ( open[0] != '<' )
|
||||
{
|
||||
sprintf(tmp_reason, "malformed opening tag (should be <%s __type\"option_type\">)", open);
|
||||
*reason = strdup(tmp_reason);
|
||||
return false;
|
||||
}
|
||||
if ( close[0] != '<' || close[1] != '/' || close[strlen(close)-1] != '>' )
|
||||
{
|
||||
sprintf(tmp_reason, "malformed closing tag (should be </%s>)", open+1);
|
||||
*reason = strdup(tmp_reason);
|
||||
return false;
|
||||
}
|
||||
if ( close[strlen(open)+1] != '>' || strncmp(open+1, close+2, strlen(open+1)) != 0 )
|
||||
{
|
||||
sprintf(tmp_reason, "opening tag doesn't match closing tag (%s> vs %s)", open, close);
|
||||
*reason = strdup(tmp_reason);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* type errors */
|
||||
if ( strcmp(option_type, expected_type) != 0 )
|
||||
{
|
||||
sprintf(tmp_reason, "unexpected type (expected %s, got %s)", expected_type, option_type);
|
||||
*reason = strdup(tmp_reason);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( type == PSMAP_PROPERTY_TYPE_STR )
|
||||
{
|
||||
if ( strlen(value) > member_width-1 )
|
||||
{
|
||||
sprintf(tmp_reason, "value %s too long (max length is %d, got %d)", value, member_width-1, strlen(value));
|
||||
*reason = strdup(tmp_reason);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( type == PSMAP_PROPERTY_TYPE_ATTR )
|
||||
return true; // can't do further checks
|
||||
|
||||
if ( type == PSMAP_PROPERTY_TYPE_FLOAT )
|
||||
{
|
||||
char *endPtr;
|
||||
(void)strtof(value, &endPtr);
|
||||
if ( endPtr != (value+strlen(value)) || errno == ERANGE )
|
||||
{
|
||||
sprintf(tmp_reason, "invalid %s value %s (should be a valid IEEE 754 floating point number)", option_type, value);
|
||||
*reason = strdup(tmp_reason);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( type == PSMAP_PROPERTY_TYPE_BOOL )
|
||||
{
|
||||
if ( strlen(value) != 1 || (value[0] != '0' && value[0] != '1') )
|
||||
{
|
||||
sprintf(tmp_reason, "invalid bool value (should be 0 or 1, got %s)", value);
|
||||
*reason = strdup(tmp_reason);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( type == PSMAP_PROPERTY_TYPE_U64 )
|
||||
{
|
||||
char *endPtr;
|
||||
(void)strtoull(value, &endPtr, 10);
|
||||
if ( endPtr != (value+strlen(value)) || errno == ERANGE )
|
||||
{
|
||||
sprintf(tmp_reason, "invalid %s value %s (should be an integer between 0 and 18446744073709551615)", option_type, value);
|
||||
*reason = strdup(tmp_reason);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else // only numeric types up to S64 remain
|
||||
{
|
||||
char *endPtr;
|
||||
int64_t parsed = strtoull(value, &endPtr, 10);
|
||||
if ( type == PSMAP_PROPERTY_TYPE_S64 && errno == ERANGE )
|
||||
{
|
||||
sprintf(tmp_reason, "invalid %s value (should be an integer between -9223372036854775808 and 9223372036854775807)", option_type);
|
||||
*reason = strdup(tmp_reason);
|
||||
return false;
|
||||
}
|
||||
else if ( endPtr != (value+strlen(value)) )
|
||||
{
|
||||
sprintf(tmp_reason, "invalid value %s (should be an integer and nothing else)", value);
|
||||
*reason = strdup(tmp_reason);
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t min = get_min((enum psmap_property_type)type);
|
||||
int64_t max = get_max((enum psmap_property_type)type);
|
||||
if ( parsed < min || parsed > max )
|
||||
{
|
||||
sprintf(tmp_reason, "invalid value (should be an integer between %lld and %lld, got %s)", min, max, value);
|
||||
*reason = strdup(tmp_reason);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void config_diag(const char *opt_filepath, const struct property_psmap *psmap) {
|
||||
int i = 0;
|
||||
int shift = strlen("/popnhax/");
|
||||
FILE *opt = fopen(opt_filepath, "r");
|
||||
if ( opt == NULL )
|
||||
{
|
||||
LOG("FATAL ERROR: cannot open %s\n", opt_filepath);
|
||||
}
|
||||
|
||||
while ( psmap[i].type != 0xFF )
|
||||
{
|
||||
bool required = !psmap[i].has_default;
|
||||
const char *option_name = psmap[i].path+shift;
|
||||
//LOG("checking %s option %s\n", required ? "REQUIRED" : "OPTIONAL", option_name);
|
||||
char *option_line = get_option(opt, (char*)option_name); //will return NULL if option_name is NULL
|
||||
if (option_line)
|
||||
{
|
||||
char *reason;
|
||||
if (!is_valid(option_line, psmap[i].type, psmap[i].member_width, &reason))
|
||||
{
|
||||
LOG("\t%s", option_line);
|
||||
LOG("ERROR: %s: %s\n", option_name, reason);
|
||||
}
|
||||
}
|
||||
else if (required)
|
||||
{
|
||||
LOG("ERROR: required option %s not found\n", option_name);
|
||||
}
|
||||
free(option_line);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// take care of updating .xml/.opt files if needed
|
||||
bool config_process(const char *xml_filepath){
|
||||
// look for _update marker file
|
||||
@ -239,4 +506,4 @@ bool config_process(const char *xml_filepath){
|
||||
bool res = config_make_opt(xml_filepath);
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
@ -73,5 +73,6 @@ struct popnhax_config {
|
||||
};
|
||||
|
||||
bool config_process(const char *filepath); // take care of updating .xml/.opt files if needed
|
||||
void config_diag(const char *xml_filepath, const struct property_psmap *psmap);
|
||||
|
||||
#endif
|
||||
|
@ -7917,7 +7917,8 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
|
||||
|
||||
if (!_load_config(g_config_fn, &config, config_psmap))
|
||||
{
|
||||
LOG("FATAL ERROR: Could not parse %s\n", g_config_fn);
|
||||
LOG("popnhax: FATAL ERROR: failed to load %s. Running advanced diagnostic...\n", g_config_fn);
|
||||
config_diag(g_config_fn, config_psmap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
47
util/psmap.h
Normal file
47
util/psmap.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef __PSMAP_H__
|
||||
#define __PSMAP_H__
|
||||
|
||||
struct property_psmap {
|
||||
uint8_t type;
|
||||
uint8_t has_default;
|
||||
uint16_t field_offset;
|
||||
uint32_t member_width;
|
||||
const char *path;
|
||||
uintptr_t default_value;
|
||||
} __attribute__((packed));
|
||||
|
||||
enum psmap_property_type {
|
||||
PSMAP_PROPERTY_TYPE_S8 = 0x02,
|
||||
PSMAP_PROPERTY_TYPE_U8 = 0x03,
|
||||
PSMAP_PROPERTY_TYPE_S16 = 0x04,
|
||||
PSMAP_PROPERTY_TYPE_U16 = 0x05,
|
||||
PSMAP_PROPERTY_TYPE_S32 = 0x06,
|
||||
PSMAP_PROPERTY_TYPE_U32 = 0x07,
|
||||
PSMAP_PROPERTY_TYPE_S64 = 0x08,
|
||||
PSMAP_PROPERTY_TYPE_U64 = 0x09,
|
||||
PSMAP_PROPERTY_TYPE_STR = 0x0A,
|
||||
PSMAP_PROPERTY_TYPE_FLOAT = 0x0D,
|
||||
PSMAP_PROPERTY_TYPE_ATTR = 0x2D,
|
||||
PSMAP_PROPERTY_TYPE_BOOL = 0x32,
|
||||
};
|
||||
|
||||
#ifndef __offsetof
|
||||
#define __offsetof(_s, _f) __builtin_offsetof(_s, _f)
|
||||
#endif
|
||||
|
||||
#ifndef __fieldwidth
|
||||
#define __fieldwidth(_s, _f) sizeof((((_s *)NULL)->_f))
|
||||
#endif
|
||||
|
||||
#define PSMAP_BEGIN(_name, _type) const _type struct property_psmap _name[] = {
|
||||
#define PSMAP_MEMBER_REQ(_type, _struct, _member, _path) \
|
||||
{_type, false, __offsetof(_struct, _member), __fieldwidth(_struct, _member), _path, 0},
|
||||
#define PSMAP_MEMBER_OPT(_type, _struct, _member, _path, _def) \
|
||||
{_type, true, __offsetof(_struct, _member), __fieldwidth(_struct, _member), \
|
||||
_path, (uintptr_t)_def},
|
||||
#define PSMAP_END \
|
||||
{ 0xff, false, 0, 0, "NULL", 0 } \
|
||||
} \
|
||||
;
|
||||
|
||||
#endif
|
@ -5,49 +5,7 @@
|
||||
|
||||
#include "imports/avs.h"
|
||||
#include "util/membuf.h"
|
||||
|
||||
struct property_psmap {
|
||||
uint8_t type;
|
||||
uint8_t has_default;
|
||||
uint16_t field_offset;
|
||||
uint32_t member_width;
|
||||
const char *path;
|
||||
uintptr_t default_value;
|
||||
} __attribute__((packed));
|
||||
|
||||
enum psmap_property_type {
|
||||
PSMAP_PROPERTY_TYPE_S8 = 0x02,
|
||||
PSMAP_PROPERTY_TYPE_U8 = 0x03,
|
||||
PSMAP_PROPERTY_TYPE_S16 = 0x04,
|
||||
PSMAP_PROPERTY_TYPE_U16 = 0x05,
|
||||
PSMAP_PROPERTY_TYPE_S32 = 0x06,
|
||||
PSMAP_PROPERTY_TYPE_U32 = 0x07,
|
||||
PSMAP_PROPERTY_TYPE_S64 = 0x08,
|
||||
PSMAP_PROPERTY_TYPE_U64 = 0x09,
|
||||
PSMAP_PROPERTY_TYPE_STR = 0x0A,
|
||||
PSMAP_PROPERTY_TYPE_FLOAT = 0x0D,
|
||||
PSMAP_PROPERTY_TYPE_ATTR = 0x2D,
|
||||
PSMAP_PROPERTY_TYPE_BOOL = 0x32,
|
||||
};
|
||||
|
||||
#ifndef __offsetof
|
||||
#define __offsetof(_s, _f) __builtin_offsetof(_s, _f)
|
||||
#endif
|
||||
|
||||
#ifndef __fieldwidth
|
||||
#define __fieldwidth(_s, _f) sizeof((((_s *)NULL)->_f))
|
||||
#endif
|
||||
|
||||
#define PSMAP_BEGIN(_name, _type) const _type struct property_psmap _name[] = {
|
||||
#define PSMAP_MEMBER_REQ(_type, _struct, _member, _path) \
|
||||
{_type, false, __offsetof(_struct, _member), __fieldwidth(_struct, _member), _path, 0},
|
||||
#define PSMAP_MEMBER_OPT(_type, _struct, _member, _path, _def) \
|
||||
{_type, true, __offsetof(_struct, _member), __fieldwidth(_struct, _member), \
|
||||
_path, (uintptr_t)_def},
|
||||
#define PSMAP_END \
|
||||
{ 0xff, false, 0, 0, "NULL", 0 } \
|
||||
} \
|
||||
;
|
||||
#include "util/psmap.h"
|
||||
|
||||
int reader_callback(uint32_t context, void *bytes, size_t nbytes) {
|
||||
return fread(bytes, 1, nbytes, (FILE *)TlsGetValue(context));
|
||||
@ -127,13 +85,7 @@ struct property *load_prop_file(const char *filename) {
|
||||
bool _load_config(const char *filename, void *dest, const struct property_psmap *psmap) {
|
||||
struct property *config_xml = load_prop_file(filename);
|
||||
|
||||
if (!config_xml) {
|
||||
printf("Couldn't load xml file: %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(property_psmap_import(config_xml, nullptr, dest, psmap))) {
|
||||
printf("Couldn't parse psmap\n");
|
||||
if (!config_xml || !(property_psmap_import(config_xml, nullptr, dest, psmap))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user