diff options
Diffstat (limited to 'docs/release/src/osd/winui/history.cpp')
-rw-r--r-- | docs/release/src/osd/winui/history.cpp | 346 |
1 files changed, 272 insertions, 74 deletions
diff --git a/docs/release/src/osd/winui/history.cpp b/docs/release/src/osd/winui/history.cpp index b4cdfe718f6..2e222129bdd 100644 --- a/docs/release/src/osd/winui/history.cpp +++ b/docs/release/src/osd/winui/history.cpp @@ -23,6 +23,12 @@ * - Each table must contain at least MAX_HFILES members (extra lines * are ignored) * - Software comes first, followed by Game then Source. + + * 2023-06: Robbbert + * - Added support for history.xml + * - Dropped support for history.dat + * - HBMAME: Dropped support for messinfo.dat, sysinfo.dat, story.dat, marp.dat + ***************************************************************************/ // license:BSD-3-Clause // copyright-holders:Chris Kirmse, Mike Haaland, René Single, Mamesick, Robbbert @@ -39,6 +45,7 @@ #include "mui_opts.h" #include "emu_opts.h" #include "sound/samples.h" +#include "path.h" /**************************************************************************** @@ -63,39 +70,27 @@ HSOURCEINFO; /*************************** START CONFIGURABLE AREA *******************************/ // number of dats we support -#define MAX_HFILES 8 +#define MAX_HFILES 4 // The order of these is the order they are displayed const HGAMEINFO m_gameInfo[MAX_HFILES] = { - { "history.dat", "\n**** :HISTORY: ****\n\n", "$bio", 1 }, - { "sysinfo.dat", "\n**** :SYSINFO: ****\n\n", "$bio", 1 }, - { "messinfo.dat", "\n**** :MESSINFO: ****\n\n", "$mame", 1 }, + { "history.xml", "\n**** :HISTORY: ****\n\n", "<text>", 1 }, { "mameinfo.dat", "\n**** :MAMEINFO: ****\n\n", "$mame", 1 }, { "gameinit.dat", "\n**** :GAMEINIT: ****\n\n", "$mame", 1 }, { "command.dat", "\n**** :COMMANDS: ****\n\n", "$cmd", 1 }, - { "story.dat", "\n**** :HIGH SCORES: ****\n\n", "$story", 0 }, - { "marp.dat", "\n**** :MARP HIGH SCORES: ****\n\n", "$marp", 0 }, }; const HSOURCEINFO m_sourceInfo[MAX_HFILES] = { { NULL }, - { NULL }, - { "messinfo.dat", "\n***:MESSINFO DRIVER: ", "$drv" }, { "mameinfo.dat", "\n***:MAMEINFO DRIVER: ", "$drv" }, { NULL }, { NULL }, - { NULL }, - { NULL }, }; const HSOURCEINFO m_swInfo[MAX_HFILES] = { - { "history.dat", "\n**** :HISTORY item: ", "$bio" }, - { NULL }, - { NULL }, - { NULL }, - { NULL }, + { "history.xml", "\n**** :HISTORY item: ", "<text>" }, { NULL }, { NULL }, { NULL }, @@ -105,8 +100,125 @@ const HSOURCEINFO m_swInfo[MAX_HFILES] = int file_sizes[MAX_HFILES] = { 0, }; std::map<std::string, std::streampos> mymap[MAX_HFILES]; +const size_t npos = std::string::npos; -static bool create_index(std::ifstream &fp, int filenum) +static void create_index_history(const char* datsdir, std::ifstream &fp, std::string file_line, int filenum) +{ + int what_to_do = 0; // 0 = xml not found; 1 = idx not found or version mismatch; 2 = both ok, need to read idx. + const std::string text1 = "<system name=", text4 = "\""; + std::string xml_ver, idx_ver; + size_t quot1 = npos, quot2 = npos; + + if (!fp.good()) + return; // xml not found + // get version from line 2 + std::getline(fp, file_line); + quot1 = file_line.find(text4); + if (quot1 != npos) + { + quot1++; + quot2 = file_line.find(text4, quot1); + if (quot2 != npos) + { + xml_ver = file_line.substr(quot1, quot2-quot1); + //printf("XML-VER = %s\n",xml_ver.c_str());fflush(stdout); + } + } + + std::string buf, filename = datsdir + std::string("\\history.idx"); + std::ifstream fi (filename); + if (!fi.good()) + what_to_do = 1; // idx not found + else + // get version from line 1 + { + std::getline(fi, idx_ver); + //printf("IDX-VER = %s\n",idx_ver.c_str());fflush(stdout); + if (xml_ver == idx_ver) + what_to_do = 2; + } + + //printf("*******2 %d\n",what_to_do);fflush(stdout); + // 2: just read idx into map + if (what_to_do == 2) + { + std::getline(fi, file_line); + while (fi.good()) + { + quot1 = file_line.find("="); + //std::string t4 = file_line.substr(0, quot1);printf("*** %s\n",t4.c_str());fflush(stdout); + //u32 t5 = stoi(file_line.substr(quot1+1));printf("*** %d\n",t5);fflush(stdout); + mymap[filenum][file_line.substr(0, quot1)] = stoi(file_line.substr(quot1+1)); + std::getline(fi, file_line); + } + fi.close(); + return; + } + + // 1: create idx then save it + fi.close(); + std::streampos key_position = file_line.size() + 2, text_position = 0U; // tellg is buggy, this works and is faster + while (fp.good()) + { + size_t find = file_line.find(text1); + std::string final_key; + if (find != npos) // found a system + { + // Find position of the 2 double-quotes + quot1 = file_line.find(text4); + if (quot1 != npos) + { + quot1++; + quot2 = file_line.find(text4, quot1); + if (quot2 != npos) + final_key = file_line.substr(quot1, quot2-quot1); + } + } + // If we passed the tests we now have the key, find the next text + if (!final_key.empty()) + { + bool found = false; + if (key_position > text_position) // else new key uses the same text as last time + { + // look for next text + text_position = key_position; // set to actual fp + for (;found == false;) + { + std::getline(fp, file_line); + find = file_line.find("<text>"); + if (find != npos) + { + found = true; + text_position += (find+6); + } + else + text_position += (file_line.size() + 2); + } + } + // Save info + mymap[filenum][final_key] = text_position; + } + fp.seekg(key_position); + std::getline(fp, file_line); + key_position += (file_line.size() + 2); + } + + // Save idx + FILE *f = fopen(filename.c_str(), "w"); + if (f == NULL) + { + printf("Unable to open history.idx for writing.\n"); + return; + } + + fprintf(f, "%s\n",xml_ver.c_str()); + for (auto const &it : mymap[filenum]) + fprintf(f, "%s=%d\n", it.first.c_str(), int(it.second)); + fclose(f); + +} + +static bool create_index(const char* datsdir, std::ifstream &fp, int filenum) { if (!fp.good()) return false; @@ -120,41 +232,103 @@ static bool create_index(std::ifstream &fp, int filenum) mymap[filenum].clear(); file_sizes[filenum] = file_size; fp.seekg(0); - std::string file_line, first, second; + std::string file_line; std::getline(fp, file_line); - int position = file_line.size() + 2; // tellg is buggy, this works and is faster - while (fp.good()) + if (filenum == 0) + create_index_history(datsdir, fp, file_line, filenum); + else { - char t1 = file_line[0]; - if ((std::count(file_line.begin(),file_line.end(),'=') == 1) && (t1 == '$')) // line must start with $ and contain one = + std::streampos position = file_line.size() + 2; // tellg is buggy, this works and is faster + while (fp.good()) { - // now start by removing all spaces - file_line.erase(remove_if(file_line.begin(), file_line.end(), ::isspace), file_line.end()); - char s[file_line.length()+1]; - strcpy(s, file_line.c_str()); - - const char* first = strtok(s, "="); // get first part of key - char* second = strtok(NULL, ","); // get second part - while (second) + if (file_line.find("$info=")==0) { - // store into index - mymap[filenum][std::string(first) + std::string("=") + std::string(second)] = position; - second = strtok(NULL, ","); + // now start by removing all spaces + file_line.erase(remove_if(file_line.begin(), file_line.end(), ::isspace), file_line.end()); + file_line.erase(0,6); + size_t t1 = npos; + while (file_line.length() > 0) + { + t1 = file_line.find(","); + // store into index + mymap[filenum][file_line.substr(0, t1)] = position; + if (t1 == npos) + file_line.erase(); + else + file_line.erase(0, t1+1); // erase key and comma + } } + std::getline(fp, file_line); + position += (file_line.size() + 2); } - std::getline(fp, file_line); - position += (file_line.size() + 2); } // check contents -// if (filenum == 0) -// for (auto const &it : mymap[filenum]) -// printf("%s = %X\n", it.first.c_str(), int(it.second)); +// if (filenum == 6) +// for (auto const &it : mymap[filenum]) +// printf("%s = %X\n", it.first.c_str(), int(it.second)); return true; } +static std::string convert_xml(std::string buf) +{ + // convert xml to real chars + if (!buf.empty()) + { + bool found = false; + size_t find = 0; + for (; found == false;) + { + find = buf.find("&"); + if (find != npos) + buf.replace(find,5,"&"); + else + found = true; + } + found = false; + for (; found == false;) + { + find = buf.find("'"); + if (find != npos) + buf.replace(find,6,"\'"); + else + found = true; + } + found = false; + for (; found == false;) + { + find = buf.find("""); + if (find != npos) + buf.replace(find,6,"\""); + else + found = true; + } + found = false; + for (; found == false;) + { + find = buf.find("<"); + if (find != npos) + buf.replace(find,4,"<"); + else + found = true; + } + found = false; + for (; found == false;) + { + find = buf.find(">"); + if (find != npos) + buf.replace(find,4,">"); + else + found = true; + } + } + return buf; +} + +std::string readbuf; + static std::string load_datafile_text(std::ifstream &fp, std::string keycode, int filenum, const char *tag) { - std::string readbuf; + readbuf.clear(); auto search = mymap[filenum].find(keycode); if (search != mymap[filenum].end()) @@ -163,13 +337,19 @@ static std::string load_datafile_text(std::ifstream &fp, std::string keycode, in fp.seekg(offset); std::string file_line; - /* read text until buffer is full or end of entry is encountered */ + // read text until buffer is full or end of entry is encountered while (std::getline(fp, file_line)) { - //printf("%s\n",file_line.c_str()); + //if (filenum == 6) ("*******2: %s\n",file_line.c_str()); + if (file_line == "- CONTRIBUTE -") + break; + if (file_line.find("$end")==0) break; + if (file_line.find("</text>") != npos) + break; + if (file_line.find(tag)==0) continue; @@ -180,9 +360,11 @@ static std::string load_datafile_text(std::ifstream &fp, std::string keycode, in return readbuf; } +std::string buffer; + std::string load_swinfo(const game_driver *drv, const char* datsdir, std::string software, int filenum) { - std::string buffer; + buffer.clear(); // if it's a NULL record exit now if (!m_swInfo[filenum].filename) return buffer; @@ -191,15 +373,13 @@ std::string load_swinfo(const game_driver *drv, const char* datsdir, std::string std::string buf, filename = datsdir + std::string("\\") + m_swInfo[filenum].filename; std::ifstream fp (filename); - /* try to open datafile */ - if (create_index(fp, filenum)) + // try to open datafile + if (create_index(datsdir, fp, filenum)) { size_t i = software.find(":"); - std::string ssys = software.substr(0, i); std::string ssoft = software.substr(i+1); - std::string first = std::string("$") + ssys + std::string("=") + ssoft; // get info on software - buf = load_datafile_text(fp, first, filenum, m_swInfo[filenum].descriptor); + buf = load_datafile_text(fp, software, filenum, m_swInfo[filenum].descriptor); if (!buf.empty()) buffer.append(m_swInfo[filenum].header).append(ssoft).append("\n").append(buf).append("\n\n\n"); @@ -207,12 +387,12 @@ std::string load_swinfo(const game_driver *drv, const char* datsdir, std::string fp.close(); } - return buffer; + return convert_xml(buffer); } std::string load_gameinfo(const game_driver *drv, const char* datsdir, int filenum) { - std::string buffer; + buffer.clear(); // if it's a NULL record exit now if (!m_gameInfo[filenum].filename) return buffer; @@ -221,13 +401,32 @@ std::string load_gameinfo(const game_driver *drv, const char* datsdir, int filen std::string buf, filename = datsdir + std::string("\\") + m_gameInfo[filenum].filename; std::ifstream fp (filename); - /* try to open datafile */ - if (create_index(fp, filenum)) + if (filenum == 0) { - std::string first = std::string("$info=")+drv->name; - // get info on game - buf = load_datafile_text(fp, first, filenum, m_gameInfo[filenum].descriptor); + // try to open history.xml + if (create_index(datsdir, fp, filenum)) + { + // get info on game + buf = load_datafile_text(fp, drv->name, filenum, m_gameInfo[filenum].descriptor); + // if nothing, and it's a clone, and it's allowed, try the parent + if (buf.empty() && m_gameInfo[filenum].bClone) + { + int g = driver_list::clone(*drv); + if (g != -1) + { + drv = &driver_list::driver(g); + buf = load_datafile_text(fp, drv->name, filenum, m_gameInfo[filenum].descriptor); + } + } + } + } + else + // try to open datafile + if (create_index(datsdir, fp, filenum)) + { + // get info on game + buf = load_datafile_text(fp, drv->name, filenum, m_gameInfo[filenum].descriptor); // if nothing, and it's a clone, and it's allowed, try the parent if (buf.empty() && m_gameInfo[filenum].bClone) { @@ -235,23 +434,22 @@ std::string load_gameinfo(const game_driver *drv, const char* datsdir, int filen if (g != -1) { drv = &driver_list::driver(g); - first = std::string("$info=")+drv->name; - buf = load_datafile_text(fp, first, filenum, m_gameInfo[filenum].descriptor); + buf = load_datafile_text(fp, drv->name, filenum, m_gameInfo[filenum].descriptor); } } + } - if (!buf.empty()) - buffer.append(m_gameInfo[filenum].header).append(buf).append("\n\n\n"); + if (!buf.empty()) + buffer.append(m_gameInfo[filenum].header).append(buf).append("\n\n\n"); - fp.close(); - } + fp.close(); - return buffer; + return convert_xml(buffer); } std::string load_sourceinfo(const game_driver *drv, const char* datsdir, int filenum) { - std::string buffer; + buffer.clear(); // if it's a NULL record exit now if (!m_sourceInfo[filenum].filename) return buffer; @@ -264,11 +462,10 @@ std::string load_sourceinfo(const game_driver *drv, const char* datsdir, int fil size_t i = source.find_last_of("/"); source.erase(0,i+1); - if (create_index(fp, filenum)) + if (create_index(datsdir, fp, filenum)) { - std::string first = std::string("$info=")+source; // get info on game driver source - buf = load_datafile_text(fp, first, filenum, m_sourceInfo[filenum].descriptor); + buf = load_datafile_text(fp, source, filenum, m_sourceInfo[filenum].descriptor); if (!buf.empty()) buffer.append(m_sourceInfo[filenum].header).append(source).append("\n").append(buf).append("\n\n\n"); @@ -287,9 +484,9 @@ std::string load_driver_geninfo(const game_driver *drv, int drvindex) const game_driver *parent = NULL; char name[512]; bool is_bios = false; - std::string buffer = "\n**** :GENERAL MACHINE INFO: ****\n\n"; + buffer = "\n**** :GENERAL MACHINE INFO: ****\n\n"; - /* List the game info 'flags' */ + // List the game info 'flags' uint32_t cache = GetDriverCacheLower(drvindex); if (BIT(cache, 6)) buffer.append("This game doesn't work properly\n"); @@ -329,14 +526,14 @@ std::string load_driver_geninfo(const game_driver *drv, int drvindex) if (drv->flags & MACHINE_IS_BIOS_ROOT) is_bios = true; - /* GAME INFORMATIONS */ + // GAME INFORMATIONS snprintf(name, std::size(name), "\nGAME: %s\n", drv->name); buffer.append(name); snprintf(name, std::size(name), "%s", drv->type.fullname()); buffer.append(name); snprintf(name, std::size(name), " (%s %s)\n\nCPU:\n", drv->manufacturer, drv->year); buffer.append(name); - /* iterate over CPUs */ + // iterate over CPUs execute_interface_enumerator cpuiter(config.root_device()); std::unordered_set<std::string> exectags; @@ -370,7 +567,7 @@ std::string load_driver_geninfo(const game_driver *drv, int drvindex) buffer.append("\nSOUND:\n"); int has_sound = 0; - /* iterate over sound chips */ + // iterate over sound chips sound_interface_enumerator sounditer(config.root_device()); std::unordered_set<std::string> soundtags; @@ -583,13 +780,14 @@ bool validate_datfiles(void) return result; } +std::string fullbuf; // For all of MAME builds - called by winui.cpp char * GetGameHistory(int driver_index, std::string software) { - std::string fullbuf; + fullbuf.clear(); if (driver_index < 0) - return ConvertToWindowsNewlines(fullbuf.c_str()); + return ConvertToWindowsNewlines(fullbuf.c_str()); if (validate_datfiles()) { @@ -604,7 +802,7 @@ char * GetGameHistory(int driver_index, std::string software) if (!software.empty()) { size_t i = software.find(':'); - sw_valid = (i != std::string::npos) ? true : false; + sw_valid = (i != npos) ? true : false; } if (datsdir && osd::directory::open(datsdir)) @@ -631,9 +829,9 @@ char * GetGameHistory(int driver_index, std::string software) // For Arcade-only builds char * GetGameHistory(int driver_index) { - std::string fullbuf; + fullbuf.clear(); if (driver_index < 0) - return ConvertToWindowsNewlines(fullbuf.c_str()); + return ConvertToWindowsNewlines(fullbuf.c_str()); if (validate_datfiles()) { |