diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 724e1fda6..89a97f683 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -48,6 +48,7 @@ add_executable(86Box nvr_at.c nvr_ps2.c machine_status.c + edid_parse.cpp ) if(CMAKE_SYSTEM_NAME MATCHES "Linux") diff --git a/src/edid_parse.cpp b/src/edid_parse.cpp new file mode 100644 index 000000000..241844fa3 --- /dev/null +++ b/src/edid_parse.cpp @@ -0,0 +1,120 @@ +#include +#include +#include +#include + +#include + +extern "C" +{ +#include <86box/86box.h> +#include <86box/plat.h> + +extern int ini_detect_bom(const char *fn); +extern ssize_t local_getline(char **buf, size_t *bufsiz, FILE *fp); +} + +// https://stackoverflow.com/a/64886763 +static std::vector split(const std::string str, const std::string regex_str) +{ + std::regex regexz(regex_str); + std::vector list(std::sregex_token_iterator(str.begin(), str.end(), regexz, -1), + std::sregex_token_iterator()); + return list; +} + +extern "C" +{ + bool parse_edid_decode_file(const char* path, uint8_t* out, ssize_t* size_out) + { + std::regex regexLib("^([a-f0-9]{32}|[a-f0-9 ]{47})$", std::regex_constants::egrep); + FILE* file; + pclog("Parse %s\n", path); + try { + bool bom = ini_detect_bom(path); + { + // First check for "edid-decode (hex)" string. + file = plat_fopen(path, "rb"); + if (file) { + std::string str; + size_t size; + if (!fseek(file, 0, SEEK_END)) { + size = ftell(file); + if (size != -1) { + str.resize(size); + } + fseek(file, 0, SEEK_SET); + auto read = fread((void*)str.data(), 1, size, file); + str.resize(read); + fclose(file); + file = NULL; + + if (str.size() == 0) { + return false; + } + + if (str.find("edid-decode") == std::string::npos) { + return false; + } + } + } else { + return false; + } + } + file = plat_fopen(path, "rb"); + if (file) { + char* buf = NULL; + size_t size = 0; + std::string edid_decode_text; + fseek(file, 0, SEEK_END); + size = ftell(file); + fseek(file, 0, SEEK_SET); + if (bom) { + fseek(file, 3, SEEK_SET); + size -= 3; + } + edid_decode_text.resize(size); + auto err = fread((void*)edid_decode_text.data(), size, 1, file); + fclose(file); + file = NULL; + if (err == 0) { + return false; + } + std::istringstream isstream(edid_decode_text); + std::string line; + std::string edid; + while (std::getline(isstream, line)) { + if (line[line.size() - 1] == '\r') { + line.resize(line.size() - 1); + } + std::smatch matched; + if (std::regex_match(line, matched, regexLib)) { + edid.append(matched.str() + " "); + } + } + if (edid.size() >= 3) { + edid.resize(edid.size() - 1); + auto vals = split(edid, "\\s+"); + if (vals.size()) { + *size_out = vals.size(); + if (vals.size() > 256) + return false; + for (int i = 0; i < vals.size(); i++) { + out[i] = (uint8_t)std::strtoul(&vals[i][0], nullptr, 16); + } + return true; + } + } + } + + return false; + } catch (std::bad_alloc&) { + if (file) { + fclose(file); + file = NULL; + } + return false; + } + return false; + } +} \ No newline at end of file diff --git a/src/qt/qt_settingsdisplay.cpp b/src/qt/qt_settingsdisplay.cpp index b03930806..bbe64dc00 100644 --- a/src/qt/qt_settingsdisplay.cpp +++ b/src/qt/qt_settingsdisplay.cpp @@ -46,7 +46,7 @@ SettingsDisplay::SettingsDisplay(QWidget *parent) for (uint8_t i = 0; i < GFXCARD_MAX; i ++) videoCard[i] = gfxcard[i]; - ui->lineEdit->setFilter(tr("EDID") % util::DlgFilter({ "bin", "dat", "edid" }) % tr("All files") % util::DlgFilter({ "*" }, true)); + ui->lineEdit->setFilter(tr("EDID") % util::DlgFilter({ "bin", "dat", "edid", "txt" }) % tr("All files") % util::DlgFilter({ "*" }, true)); onCurrentMachineChanged(machine); } diff --git a/src/utils/ini.c b/src/utils/ini.c index b267f38b5..47e792594 100644 --- a/src/utils/ini.c +++ b/src/utils/ini.c @@ -316,7 +316,7 @@ ini_close(ini_t ini) free(list); } -static int +int ini_detect_bom(const char *fn) { FILE *fp; diff --git a/src/video/vid_ddc.c b/src/video/vid_ddc.c index d6c9095ef..6d86a25c9 100644 --- a/src/video/vid_ddc.c +++ b/src/video/vid_ddc.c @@ -14,6 +14,7 @@ * * Copyright 2020 RichardG. */ +#include #include #include #include @@ -231,13 +232,36 @@ ddc_create_default_edid(ssize_t* size_out) return edid; } +extern bool parse_edid_decode_file(const char* path, uint8_t* out, ssize_t* size); + void * ddc_init(void *i2c) { ssize_t edid_size = 0; uint8_t* edid_bytes = NULL; if (monitor_edid == 1 && monitor_edid_path[0]) { - FILE* file = plat_fopen(monitor_edid_path, "rb"); + FILE* file; + { + edid_bytes = calloc(1, 256); + if (parse_edid_decode_file(monitor_edid_path, edid_bytes, &edid_size) == false) { + if (edid_size > 256) { + wchar_t errmsg[2048] = { 0 }; + wchar_t path[2048] = { 0 }; + +#ifdef _WIN32 + mbstoc16s(path, monitor_edid_path, sizeof_w(path)); +#else + mbstowcs(path, monitor_edid_path, sizeof_w(path)); +#endif + swprintf(errmsg, sizeof_w(errmsg), plat_get_string(STRING_EDID_TOO_LARGE), path); + ui_msgbox_header(MBX_ERROR, L"EDID", errmsg); + } + free(edid_bytes); + } else { + goto calculate_cksum; + } + } + file = plat_fopen(monitor_edid_path, "rb"); if (!file) goto default_init; @@ -282,6 +306,8 @@ ddc_init(void *i2c) goto default_init; } + fclose(file); +calculate_cksum: if (edid_size < 128) { edid_bytes = realloc(edid_bytes, 128); edid_size = 128; @@ -306,7 +332,6 @@ ddc_init(void *i2c) } } - fclose(file); return i2c_eeprom_init(i2c, 0x50, edid_bytes, edid_size, 0); } default_init: