/*************************************************************************** info.c Dumps the MAME internal data as an XML file. **************************************************************************** Copyright Aaron Giles All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name 'MAME' nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ #include "emu.h" #include "emuopts.h" #include "machine/ram.h" #include "sound/samples.h" #include "info.h" #include "xmlfile.h" #include "config.h" #include //************************************************************************** // GLOBAL VARIABLES //************************************************************************** // DTD string describing the data const char info_xml_creator::s_dtd_string[] = "\n" "\t\n" "\t\n" "\t\n" "\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\n" "\t\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\t\n" "]>"; //************************************************************************** // INFO XML CREATOR //************************************************************************** //------------------------------------------------- // info_xml_creator - constructor //------------------------------------------------- info_xml_creator::info_xml_creator(driver_enumerator &drivlist) : m_output(NULL), m_drivlist(drivlist), m_lookup_options(m_drivlist.options()) { m_lookup_options.remove_device_options(); } //------------------------------------------------- // output_mame_xml - print the XML information // for all known games //------------------------------------------------- void info_xml_creator::output(FILE *out) { m_output = out; // output the DTD fprintf(m_output, "\n"); astring dtd(s_dtd_string); dtd.replace(0,"__XML_ROOT__", emulator_info::get_xml_root()); dtd.replace(0,"__XML_TOP__", emulator_info::get_xml_top()); fprintf(m_output, "%s\n\n", dtd.cstr()); // top-level tag fprintf(m_output, "<%s build=\"%s\" debug=\"" #ifdef MAME_DEBUG "yes" #else "no" #endif "\" mameconfig=\"%d\">\n", emulator_info::get_xml_root(), xml_normalize_string(build_version), CONFIG_VERSION ); // iterate through the drivers, outputting one at a time while (m_drivlist.next()) output_one(); // output devices (both devices with roms and slot devices) output_devices(); // close the top level tag fprintf(m_output, "\n",emulator_info::get_xml_root()); } //------------------------------------------------- // output_one - print the XML information // for one particular game driver //------------------------------------------------- void info_xml_creator::output_one() { // no action if not a game const game_driver &driver = m_drivlist.driver(); if (driver.flags & GAME_NO_STANDALONE) return; // allocate input ports machine_config &config = m_drivlist.config(); ioport_list portlist; astring errors; device_iterator iter(config.root_device()); for (device_t *device = iter.first(); device != NULL; device = iter.next()) portlist.append(*device, errors); // print the header and the game name fprintf(m_output, "\t<%s",emulator_info::get_xml_top()); fprintf(m_output, " name=\"%s\"", xml_normalize_string(driver.name)); // strip away any path information from the source_file and output it const char *start = strrchr(driver.source_file, '/'); if (start == NULL) start = strrchr(driver.source_file, '\\'); if (start == NULL) start = driver.source_file - 1; fprintf(m_output, " sourcefile=\"%s\"", xml_normalize_string(start + 1)); // append bios and runnable flags if (driver.flags & GAME_IS_BIOS_ROOT) fprintf(m_output, " isbios=\"yes\""); if (driver.flags & GAME_NO_STANDALONE) fprintf(m_output, " runnable=\"no\""); if (driver.flags & GAME_MECHANICAL) fprintf(m_output, " ismechanical=\"yes\""); // display clone information int clone_of = m_drivlist.find(driver.parent); if (clone_of != -1 && !(m_drivlist.driver(clone_of).flags & GAME_IS_BIOS_ROOT)) fprintf(m_output, " cloneof=\"%s\"", xml_normalize_string(m_drivlist.driver(clone_of).name)); if (clone_of != -1) fprintf(m_output, " romof=\"%s\"", xml_normalize_string(m_drivlist.driver(clone_of).name)); // display sample information and close the game tag output_sampleof(); fprintf(m_output, ">\n"); // output game description if (driver.description != NULL) fprintf(m_output, "\t\t%s\n", xml_normalize_string(driver.description)); // print the year only if is a number or another allowed character (? or +) if (driver.year != NULL && strspn(driver.year, "0123456789?+") == strlen(driver.year)) fprintf(m_output, "\t\t%s\n", xml_normalize_string(driver.year)); // print the manufacturer information if (driver.manufacturer != NULL) fprintf(m_output, "\t\t%s\n", xml_normalize_string(driver.manufacturer)); // now print various additional information output_bios(); output_rom(m_drivlist.config().root_device()); output_device_roms(); output_sample(); output_chips(m_drivlist.config().root_device(), ""); output_display(m_drivlist.config().root_device(), ""); output_sound(m_drivlist.config().root_device()); output_input(portlist); output_switches(portlist, "", IPT_DIPSWITCH, "dipswitch", "dipvalue"); output_switches(portlist, "", IPT_CONFIG, "configuration", "confsetting"); output_adjusters(portlist); output_driver(); output_images(m_drivlist.config().root_device(), ""); output_slots(m_drivlist.config().root_device(), ""); output_software_list(); output_ramoptions(); // close the topmost tag fprintf(m_output, "\t\n",emulator_info::get_xml_top()); } //------------------------------------------------- // output_one_device - print the XML info for // a single device //------------------------------------------------- void info_xml_creator::output_one_device(device_t &device, const char *devtag) { bool has_speaker = FALSE, has_input = FALSE; // check if the device adds speakers to the system sound_interface_iterator snditer(device); if (snditer.first() != NULL) has_speaker = TRUE; // generate input list ioport_list portlist; astring errors; device_iterator iptiter(device); for (device_t *dev = iptiter.first(); dev != NULL; dev = iptiter.next()) portlist.append(*dev, errors); // check if the device adds player inputs (other than dsw and configs) to the system for (ioport_port *port = portlist.first(); port != NULL; port = port->next()) for (ioport_field *field = port->first_field(); field != NULL; field = field->next()) if (field->type() >= IPT_START1 && field->type() < IPT_UI_FIRST) { has_input = TRUE; break; } // start to output info fprintf(m_output, "\t<%s", emulator_info::get_xml_top()); fprintf(m_output, " name=\"%s\"", xml_normalize_string(device.shortname())); fprintf(m_output, " isdevice=\"yes\""); fprintf(m_output, " runnable=\"no\""); fprintf(m_output, ">\n"); fprintf(m_output, "\t\t%s\n", xml_normalize_string(device.name())); output_rom(device); output_chips(device, devtag); output_display(device, devtag); if (has_speaker) output_sound(device); if (has_input) output_input(portlist); output_switches(portlist, devtag, IPT_DIPSWITCH, "dipswitch", "dipvalue"); output_switches(portlist, devtag, IPT_CONFIG, "configuration", "confsetting"); output_adjusters(portlist); output_images(device, devtag); output_slots(device, devtag); fprintf(m_output, "\t\n", emulator_info::get_xml_top()); } //------------------------------------------------- // output_devices - print the XML info for devices // with roms and for devices that can be mounted // in slots //------------------------------------------------- typedef tagmap_t slot_map; void info_xml_creator::output_devices() { m_drivlist.reset(); slot_map shortnames; while (m_drivlist.next()) { // first, run through devices with roms which belongs to the default configuration device_iterator deviter(m_drivlist.config().root_device()); for (device_t *device = deviter.first(); device != NULL; device = deviter.next()) { if (device->owner() != NULL && device->rom_region() != NULL && device->shortname()!= NULL) { if (shortnames.add(device->shortname(), 0, FALSE) != TMERR_DUPLICATE) output_one_device(*device, device->tag()); } } // then, run through slot devices slot_interface_iterator iter(m_drivlist.config().root_device()); for (const device_slot_interface *slot = iter.first(); slot != NULL; slot = iter.next()) { const slot_interface* intf = slot->get_slot_interfaces(); for (int i = 0; intf && intf[i].name != NULL; i++) { astring temptag("_"); temptag.cat(intf[i].name); device_t *dev = const_cast(m_drivlist.config()).device_add(&m_drivlist.config().root_device(), temptag.cstr(), intf[i].devtype, 0); // notify this device and all its subdevices that they are now configured device_iterator subiter(*dev); for (device_t *device = subiter.first(); device != NULL; device = subiter.next()) if (!device->configured()) device->config_complete(); if (shortnames.add(dev->shortname(), 0, FALSE) != TMERR_DUPLICATE) output_one_device(*dev, temptag.cstr()); const_cast(m_drivlist.config()).device_remove(&m_drivlist.config().root_device(), temptag.cstr()); global_free(dev); } } } } //------------------------------------------------ // output_device_roms - when a driver uses roms // included in a device set, print a reference //------------------------------------------------- void info_xml_creator::output_device_roms() { device_iterator deviter(m_drivlist.config().root_device()); for (device_t *device = deviter.first(); device != NULL; device = deviter.next()) if (device->owner() != NULL && device->rom_region() != NULL && device->shortname()!= NULL) fprintf(m_output, "\t\t\n", xml_normalize_string(device->shortname())); } //------------------------------------------------ // output_sampleof - print the 'sampleof' // attribute, if appropriate //------------------------------------------------- void info_xml_creator::output_sampleof() { // iterate over sample devices samples_device_iterator iter(m_drivlist.config().root_device()); for (samples_device *device = iter.first(); device != NULL; device = iter.next()) { samples_iterator sampiter(*device); if (sampiter.altbasename() != NULL) { fprintf(m_output, " sampleof=\"%s\"", xml_normalize_string(sampiter.altbasename())); // must stop here, as there can only be one attribute of the same name return; } } } //------------------------------------------------- // output_bios - print the BIOS set for a // game //------------------------------------------------- void info_xml_creator::output_bios() { // skip if no ROMs if (m_drivlist.driver().rom == NULL) return; // iterate over ROM entries and look for BIOSes for (const rom_entry *rom = m_drivlist.driver().rom; !ROMENTRY_ISEND(rom); rom++) if (ROMENTRY_ISSYSTEM_BIOS(rom)) { // output extracted name and descriptions fprintf(m_output, "\t\t\n"); } } //------------------------------------------------- // output_rom - print the roms section of // the XML output //------------------------------------------------- void info_xml_creator::output_rom(device_t &device) { // iterate over 3 different ROM "types": BIOS, ROMs, DISKs for (int rom_type = 0; rom_type < 3; rom_type++) for (const rom_entry *region = rom_first_region(device); region != NULL; region = rom_next_region(region)) { bool is_disk = ROMREGION_ISDISKDATA(region); // disk regions only work for disks if ((is_disk && rom_type != 2) || (!is_disk && rom_type == 2)) continue; // iterate through ROM entries for (const rom_entry *rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom)) { bool is_bios = ROM_GETBIOSFLAGS(rom); const char *name = ROM_GETNAME(rom); int offset = ROM_GETOFFSET(rom); const char *merge_name = NULL; char bios_name[100]; // BIOS ROMs only apply to bioses if ((is_bios && rom_type != 0) || (!is_bios && rom_type == 0)) continue; // if we have a valid ROM and we are a clone, see if we can find the parent ROM hash_collection hashes(ROM_GETHASHDATA(rom)); if (!hashes.flag(hash_collection::FLAG_NO_DUMP)) merge_name = get_merge_name(hashes); if (&device != &m_drivlist.config().root_device()) merge_name = NULL; // scan for a BIOS name bios_name[0] = 0; if (!is_disk && is_bios) { // scan backwards through the ROM entries for (const rom_entry *brom = rom - 1; brom != m_drivlist.driver().rom; brom--) if (ROMENTRY_ISSYSTEM_BIOS(brom)) { strcpy(bios_name, ROM_GETNAME(brom)); break; } } // opening tag if (!is_disk) fprintf(m_output, "\t\t\n"); } } } //------------------------------------------------- // output_sample - print a list of all // samples referenced by a game_driver //------------------------------------------------- void info_xml_creator::output_sample() { // iterate over sample devices samples_device_iterator iter(m_drivlist.config().root_device()); for (samples_device *device = iter.first(); device != NULL; device = iter.next()) { samples_iterator sampiter(*device); tagmap_t already_printed; for (const char *samplename = sampiter.first(); samplename != NULL; samplename = sampiter.next()) { // filter out duplicates if (already_printed.add(samplename, 1) == TMERR_DUPLICATE) continue; // output the sample name fprintf(m_output, "\t\t\n", xml_normalize_string(samplename)); } } } /*------------------------------------------------- output_chips - print a list of CPU and sound chips used by a game -------------------------------------------------*/ void info_xml_creator::output_chips(device_t &device, const char *root_tag) { // iterate over executable devices execute_interface_iterator execiter(device); for (device_execute_interface *exec = execiter.first(); exec != NULL; exec = execiter.next()) { if (strcmp(exec->device().tag(), device.tag())) { astring newtag(exec->device().tag()), oldtag(":"); newtag.substr(newtag.find(oldtag.cat(root_tag)) + oldtag.len()); fprintf(m_output, "\t\tdevice().name())); fprintf(m_output, " clock=\"%d\"", exec->device().clock()); fprintf(m_output, "/>\n"); } } // iterate over sound devices sound_interface_iterator sounditer(device); for (device_sound_interface *sound = sounditer.first(); sound != NULL; sound = sounditer.next()) { if (strcmp(sound->device().tag(), device.tag())) { astring newtag(sound->device().tag()), oldtag(":"); newtag.substr(newtag.find(oldtag.cat(root_tag)) + oldtag.len()); fprintf(m_output, "\t\tdevice().name())); if (sound->device().clock() != 0) fprintf(m_output, " clock=\"%d\"", sound->device().clock()); fprintf(m_output, "/>\n"); } } } //------------------------------------------------- // output_display - print a list of all the // displays //------------------------------------------------- void info_xml_creator::output_display(device_t &device, const char *root_tag) { // iterate over screens screen_device_iterator iter(device); for (const screen_device *screendev = iter.first(); screendev != NULL; screendev = iter.next()) { if (strcmp(screendev->tag(), device.tag())) { astring newtag(screendev->tag()), oldtag(":"); newtag.substr(newtag.find(oldtag.cat(root_tag)) + oldtag.len()); fprintf(m_output, "\t\tscreen_type()) { case SCREEN_TYPE_RASTER: fprintf(m_output, " type=\"raster\""); break; case SCREEN_TYPE_VECTOR: fprintf(m_output, " type=\"vector\""); break; case SCREEN_TYPE_LCD: fprintf(m_output, " type=\"lcd\""); break; default: fprintf(m_output, " type=\"unknown\""); break; } // output the orientation as a string switch (m_drivlist.driver().flags & ORIENTATION_MASK) { case ORIENTATION_FLIP_X: fprintf(m_output, " rotate=\"0\" flipx=\"yes\""); break; case ORIENTATION_FLIP_Y: fprintf(m_output, " rotate=\"180\" flipx=\"yes\""); break; case ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y: fprintf(m_output, " rotate=\"180\""); break; case ORIENTATION_SWAP_XY: fprintf(m_output, " rotate=\"90\" flipx=\"yes\""); break; case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X: fprintf(m_output, " rotate=\"90\""); break; case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_Y: fprintf(m_output, " rotate=\"270\""); break; case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y: fprintf(m_output, " rotate=\"270\" flipx=\"yes\""); break; default: fprintf(m_output, " rotate=\"0\""); break; } // output width and height only for games that are not vector if (screendev->screen_type() != SCREEN_TYPE_VECTOR) { const rectangle &visarea = screendev->visible_area(); fprintf(m_output, " width=\"%d\"", visarea.width()); fprintf(m_output, " height=\"%d\"", visarea.height()); } // output refresh rate fprintf(m_output, " refresh=\"%f\"", ATTOSECONDS_TO_HZ(screendev->refresh_attoseconds())); // output raw video parameters only for games that are not vector // and had raw parameters specified if (screendev->screen_type() != SCREEN_TYPE_VECTOR && !screendev->oldstyle_vblank_supplied()) { int pixclock = screendev->width() * screendev->height() * ATTOSECONDS_TO_HZ(screendev->refresh_attoseconds()); fprintf(m_output, " pixclock=\"%d\"", pixclock); fprintf(m_output, " htotal=\"%d\"", screendev->width()); fprintf(m_output, " hbend=\"%d\"", screendev->visible_area().min_x); fprintf(m_output, " hbstart=\"%d\"", screendev->visible_area().max_x+1); fprintf(m_output, " vtotal=\"%d\"", screendev->height()); fprintf(m_output, " vbend=\"%d\"", screendev->visible_area().min_y); fprintf(m_output, " vbstart=\"%d\"", screendev->visible_area().max_y+1); } fprintf(m_output, " />\n"); } } } //------------------------------------------------- // output_sound - print a list of all the // speakers //------------------------------------------------ void info_xml_creator::output_sound(device_t &device) { speaker_device_iterator spkiter(device); int speakers = spkiter.count(); // if we have no sound, zero m_output the speaker count sound_interface_iterator snditer(device); if (snditer.first() == NULL) speakers = 0; fprintf(m_output, "\t\t\n", speakers); } //------------------------------------------------- // output_input - print a summary of a game's // input //------------------------------------------------- void info_xml_creator::output_input(const ioport_list &portlist) { // enumerated list of control types enum { ANALOG_TYPE_PADDLE, ANALOG_TYPE_PEDAL, ANALOG_TYPE_JOYSTICK, ANALOG_TYPE_POSITIONAL, ANALOG_TYPE_LIGHTGUN, ANALOG_TYPE_DIAL, ANALOG_TYPE_TRACKBALL, ANALOG_TYPE_MOUSE, ANALOG_TYPE_COUNT }; // directions const UINT8 DIR_UP = 0x01; const UINT8 DIR_DOWN = 0x02; const UINT8 DIR_LEFT = 0x04; const UINT8 DIR_RIGHT = 0x08; const UINT8 DIR_4WAY = 0x10; // initialize the list of control types struct { const char * type; /* general type of input */ bool analog; bool keyb; INT32 min; /* analog minimum value */ INT32 max; /* analog maximum value */ INT32 sensitivity; /* default analog sensitivity */ INT32 keydelta; /* default analog keydelta */ bool reverse; /* default analog reverse setting */ } control_info[ANALOG_TYPE_COUNT]; memset(&control_info, 0, sizeof(control_info)); // tracking info as we iterate int nplayer = 0; int nbutton = 0; int ncoin = 0; UINT8 joytype[3] = { 0,0,0 }; bool service = false; bool tilt = false; bool keypad = false; bool keyboard = false; bool mahjong = false; bool hanafuda = false; bool gambling = false; // iterate over the ports for (ioport_port *port = portlist.first(); port != NULL; port = port->next()) for (ioport_field *field = port->first_field(); field != NULL; field = field->next()) { int analogtype = -1; // track the highest player number if (nplayer < field->player() + 1) nplayer = field->player() + 1; // switch off of the type switch (field->type()) { // map which joystick directions are present case IPT_JOYSTICK_UP: joytype[0] |= DIR_UP | ((field->way() == 4) ? DIR_4WAY : 0); break; case IPT_JOYSTICK_DOWN: joytype[0] |= DIR_DOWN | ((field->way() == 4) ? DIR_4WAY : 0); break; case IPT_JOYSTICK_LEFT: joytype[0] |= DIR_LEFT | ((field->way() == 4) ? DIR_4WAY : 0); break; case IPT_JOYSTICK_RIGHT: joytype[0] |= DIR_RIGHT | ((field->way() == 4) ? DIR_4WAY : 0); break; case IPT_JOYSTICKLEFT_UP: joytype[1] |= DIR_UP | ((field->way() == 4) ? DIR_4WAY : 0); break; case IPT_JOYSTICKLEFT_DOWN: joytype[1] |= DIR_DOWN | ((field->way() == 4) ? DIR_4WAY : 0); break; case IPT_JOYSTICKLEFT_LEFT: joytype[1] |= DIR_LEFT | ((field->way() == 4) ? DIR_4WAY : 0); break; case IPT_JOYSTICKLEFT_RIGHT: joytype[1] |= DIR_RIGHT | ((field->way() == 4) ? DIR_4WAY : 0); break; case IPT_JOYSTICKRIGHT_UP: joytype[2] |= DIR_UP | ((field->way() == 4) ? DIR_4WAY : 0); break; case IPT_JOYSTICKRIGHT_DOWN: joytype[2] |= DIR_DOWN | ((field->way() == 4) ? DIR_4WAY : 0); break; case IPT_JOYSTICKRIGHT_LEFT: joytype[2] |= DIR_LEFT | ((field->way() == 4) ? DIR_4WAY : 0); break; case IPT_JOYSTICKRIGHT_RIGHT: joytype[2] |= DIR_RIGHT | ((field->way() == 4) ? DIR_4WAY : 0); break; // mark as an analog input, and get analog stats after switch case IPT_AD_STICK_X: case IPT_AD_STICK_Y: case IPT_AD_STICK_Z: control_info[analogtype = ANALOG_TYPE_JOYSTICK].type = "stick"; break; case IPT_PADDLE: case IPT_PADDLE_V: control_info[analogtype = ANALOG_TYPE_PADDLE].type = "paddle"; break; case IPT_PEDAL: case IPT_PEDAL2: case IPT_PEDAL3: control_info[analogtype = ANALOG_TYPE_PEDAL].type = "pedal"; break; case IPT_LIGHTGUN_X: case IPT_LIGHTGUN_Y: control_info[analogtype = ANALOG_TYPE_LIGHTGUN].type = "lightgun"; break; case IPT_POSITIONAL: case IPT_POSITIONAL_V: control_info[analogtype = ANALOG_TYPE_POSITIONAL].type = "positional"; break; case IPT_DIAL: case IPT_DIAL_V: control_info[analogtype = ANALOG_TYPE_DIAL].type = "dial"; break; case IPT_TRACKBALL_X: case IPT_TRACKBALL_Y: control_info[analogtype = ANALOG_TYPE_TRACKBALL].type = "trackball"; break; case IPT_MOUSE_X: case IPT_MOUSE_Y: control_info[analogtype = ANALOG_TYPE_MOUSE].type = "mouse"; break; // track maximum button index case IPT_BUTTON1: case IPT_BUTTON2: case IPT_BUTTON3: case IPT_BUTTON4: case IPT_BUTTON5: case IPT_BUTTON6: case IPT_BUTTON7: case IPT_BUTTON8: case IPT_BUTTON9: case IPT_BUTTON10: case IPT_BUTTON11: case IPT_BUTTON12: case IPT_BUTTON13: case IPT_BUTTON14: case IPT_BUTTON15: case IPT_BUTTON16: nbutton = MAX(nbutton, field->type() - IPT_BUTTON1 + 1); break; // track maximum coin index case IPT_COIN1: case IPT_COIN2: case IPT_COIN3: case IPT_COIN4: case IPT_COIN5: case IPT_COIN6: case IPT_COIN7: case IPT_COIN8: ncoin = MAX(ncoin, field->type() - IPT_COIN1 + 1); break; // track presence of these guys case IPT_KEYPAD: keypad = true; break; case IPT_KEYBOARD: keyboard = true; break; // additional types case IPT_SERVICE: service = true; break; case IPT_TILT: tilt = true; break; default: if (field->type() > IPT_MAHJONG_FIRST && field->type() < IPT_MAHJONG_LAST) mahjong = true; else if (field->type() > IPT_HANAFUDA_FIRST && field->type() < IPT_HANAFUDA_LAST) hanafuda = true; else if (field->type() > IPT_GAMBLING_FIRST && field->type() < IPT_GAMBLING_LAST) gambling = true; break; } // get the analog stats if (analogtype != -1) { if (field->minval() != 0) control_info[analogtype].min = field->minval(); if (field->maxval() != 0) control_info[analogtype].max = field->maxval(); if (field->sensitivity() != 0) control_info[analogtype].sensitivity = field->sensitivity(); if (field->delta() != 0) control_info[analogtype].keydelta = field->delta(); if (field->analog_reverse() != 0) control_info[analogtype].reverse = true; } } // output the basic info fprintf(m_output, "\t\t\n"); // output the joystick types if (joytype[1]==0 && joytype[2]!=0) { joytype[1] = joytype[2]; joytype[2] = 0; } if (joytype[0]==0 && joytype[1]!=0) { joytype[0] = joytype[1]; joytype[1] = 0; } if (joytype[1]==0 && joytype[2]!=0) { joytype[1] = joytype[2]; joytype[2] = 0; } if (joytype[0] != 0) { const char *joys = (joytype[2]!=0) ? "triple" : (joytype[1]!=0) ? "double" : ""; fprintf(m_output, "\t\t\t\n"); } // output analog types for (int type = 0; type < ANALOG_TYPE_COUNT; type++) if (control_info[type].type != NULL) { fprintf(m_output, "\t\t\t\n"); } // output keypad and keyboard if (keypad) fprintf(m_output, "\t\t\t\n"); if (keyboard) fprintf(m_output, "\t\t\t\n"); // misc if (mahjong) fprintf(m_output, "\t\t\t\n"); if (hanafuda) fprintf(m_output, "\t\t\t\n"); if (gambling) fprintf(m_output, "\t\t\t\n"); fprintf(m_output, "\t\t\n"); } //------------------------------------------------- // output_switches - print the configurations or // DIP switch settings //------------------------------------------------- void info_xml_creator::output_switches(const ioport_list &portlist, const char *root_tag, int type, const char *outertag, const char *innertag) { // iterate looking for DIP switches for (ioport_port *port = portlist.first(); port != NULL; port = port->next()) for (ioport_field *field = port->first_field(); field != NULL; field = field->next()) if (field->type() == type) { astring newtag(port->tag()), oldtag(":"); newtag.substr(newtag.find(oldtag.cat(root_tag)) + oldtag.len()); // output the switch name information fprintf(m_output, "\t\t<%s name=\"%s\"", outertag, xml_normalize_string(field->name())); fprintf(m_output, " tag=\"%s\"", xml_normalize_string(newtag)); fprintf(m_output, " mask=\"%u\"", field->mask()); fprintf(m_output, ">\n"); // loop over settings for (ioport_setting *setting = field->first_setting(); setting != NULL; setting = setting->next()) { fprintf(m_output, "\t\t\t<%s name=\"%s\"", innertag, xml_normalize_string(setting->name())); fprintf(m_output, " value=\"%u\"", setting->value()); if (setting->value() == field->defvalue()) fprintf(m_output, " default=\"yes\""); fprintf(m_output, "/>\n"); } // terminate the switch entry fprintf(m_output, "\t\t\n", outertag); } } //------------------------------------------------- // output_adjusters - print the Analog // Adjusters for a game //------------------------------------------------- void info_xml_creator::output_adjusters(const ioport_list &portlist) { // iterate looking for Adjusters for (ioport_port *port = portlist.first(); port != NULL; port = port->next()) for (ioport_field *field = port->first_field(); field != NULL; field = field->next()) if (field->type() == IPT_ADJUSTER) fprintf(m_output, "\t\t\n", xml_normalize_string(field->name()), field->defvalue()); } //------------------------------------------------- // output_driver - print driver status //------------------------------------------------- void info_xml_creator::output_driver() { fprintf(m_output, "\t\t\n"); } //------------------------------------------------- // output_images - prints m_output all info on // image devices //------------------------------------------------- void info_xml_creator::output_images(device_t &device, const char *root_tag) { image_interface_iterator iter(device); for (const device_image_interface *imagedev = iter.first(); imagedev != NULL; imagedev = iter.next()) { if (strcmp(imagedev->device().tag(), device.tag())) { astring newtag(imagedev->device().tag()), oldtag(":"); newtag.substr(newtag.find(oldtag.cat(root_tag)) + oldtag.len()); // print m_output device type fprintf(m_output, "\t\timage_type_name())); // does this device have a tag? if (imagedev->device().tag()) fprintf(m_output, " tag=\"%s\"", xml_normalize_string(newtag)); // is this device mandatory? if (imagedev->must_be_loaded()) fprintf(m_output, " mandatory=\"1\""); if (imagedev->image_interface() && imagedev->image_interface()[0]) fprintf(m_output, " interface=\"%s\"", xml_normalize_string(imagedev->image_interface())); // close the XML tag fprintf(m_output, ">\n"); const char *name = imagedev->instance_name(); const char *shortname = imagedev->brief_instance_name(); fprintf(m_output, "\t\t\t\n"); astring extensions(imagedev->file_extensions()); char *ext = strtok((char *)extensions.cstr(), ","); while (ext != NULL) { fprintf(m_output, "\t\t\t\n"); ext = strtok(NULL, ","); } fprintf(m_output, "\t\t\n"); } } } //------------------------------------------------- // output_images - prints all info about slots //------------------------------------------------- void info_xml_creator::output_slots(device_t &device, const char *root_tag) { slot_interface_iterator iter(device); for (const device_slot_interface *slot = iter.first(); slot != NULL; slot = iter.next()) { if (slot->fixed()) continue; // or shall we list these as non-configurable? if (strcmp(slot->device().tag(), device.tag())) { astring newtag(slot->device().tag()), oldtag(":"); newtag.substr(newtag.find(oldtag.cat(root_tag)) + oldtag.len()); // print m_output device type fprintf(m_output, "\t\t\n", xml_normalize_string(newtag)); /* if (slot->slot_interface()[0]) fprintf(m_output, " interface=\"%s\"", xml_normalize_string(slot->slot_interface())); */ const slot_interface* intf = slot->get_slot_interfaces(); for (int i = 0; intf && intf[i].name != NULL && !intf[i].internal; i++) { device_t *dev = const_cast(m_drivlist.config()).device_add(&m_drivlist.config().root_device(), "dummy", intf[i].devtype, 0); if (!dev->configured()) dev->config_complete(); fprintf(m_output, "\t\t\tshortname())); if (slot->get_default_card()) { if (strcmp(slot->get_default_card(),intf[i].name)==0) fprintf(m_output, " default=\"yes\""); } fprintf(m_output, "/>\n"); const_cast(m_drivlist.config()).device_remove(&m_drivlist.config().root_device(), "dummy"); } fprintf(m_output, "\t\t\n"); } } } //------------------------------------------------- // output_software_list - print the information // for all known software lists for this system //------------------------------------------------- void info_xml_creator::output_software_list() { software_list_device_iterator iter(m_drivlist.config().root_device()); for (const software_list_device *swlist = iter.first(); swlist != NULL; swlist = iter.next()) { fprintf(m_output, "\t\tlist_name()); fprintf(m_output, "status=\"%s\" ", (swlist->list_type() == SOFTWARE_LIST_ORIGINAL_SYSTEM) ? "original" : "compatible"); if (swlist->filter()) { fprintf(m_output, "filter=\"%s\" ", swlist->filter()); } fprintf(m_output, "/>\n"); } } //------------------------------------------------- // output_ramoptions - prints m_output all RAM // options for this system //------------------------------------------------- void info_xml_creator::output_ramoptions() { ram_device_iterator iter(m_drivlist.config().root_device()); for (const ram_device *ram = iter.first(); ram != NULL; ram = iter.next()) { fprintf(m_output, "\t\t%u\n", ram->default_size()); if (ram->extra_options() != NULL) { astring options(ram->extra_options()); for (int start = 0, end = options.chr(0, ','); ; start = end + 1, end = options.chr(start, ',')) { astring option; option.cpysubstr(options, start, (end == -1) ? -1 : end - start); fprintf(m_output, "\t\t%u\n", ram_device::parse_string(option)); if (end == -1) break; } } } } //------------------------------------------------- // get_merge_name - get the rom name from a // parent set //------------------------------------------------- const char *info_xml_creator::get_merge_name(const hash_collection &romhashes) { // walk the parent chain const char *merge_name = NULL; for (int clone_of = m_drivlist.find(m_drivlist.driver().parent); clone_of != -1; clone_of = m_drivlist.find(m_drivlist.driver(clone_of).parent)) { // look in the parent's ROMs device_iterator deviter(m_drivlist.config(clone_of, m_lookup_options).root_device()); for (device_t *device = deviter.first(); device != NULL; device = deviter.next()) for (const rom_entry *pregion = rom_first_region(*device); pregion != NULL; pregion = rom_next_region(pregion)) for (const rom_entry *prom = rom_first_file(pregion); prom != NULL; prom = rom_next_file(prom)) { hash_collection phashes(ROM_GETHASHDATA(prom)); if (!phashes.flag(hash_collection::FLAG_NO_DUMP) && romhashes == phashes) { // stop when we find a match merge_name = ROM_GETNAME(prom); break; } } } return merge_name; }