summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/info.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/info.c')
-rw-r--r--trunk/src/emu/info.c1380
1 files changed, 1380 insertions, 0 deletions
diff --git a/trunk/src/emu/info.c b/trunk/src/emu/info.c
new file mode 100644
index 00000000000..62fe531e094
--- /dev/null
+++ b/trunk/src/emu/info.c
@@ -0,0 +1,1380 @@
+/***************************************************************************
+
+ 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 <ctype.h>
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// DTD string describing the data
+const char info_xml_creator::s_dtd_string[] =
+"<!DOCTYPE __XML_ROOT__ [\n"
+"<!ELEMENT __XML_ROOT__ (__XML_TOP__+)>\n"
+"\t<!ATTLIST __XML_ROOT__ build CDATA #IMPLIED>\n"
+"\t<!ATTLIST __XML_ROOT__ debug (yes|no) \"no\">\n"
+"\t<!ATTLIST __XML_ROOT__ mameconfig CDATA #REQUIRED>\n"
+"\t<!ELEMENT __XML_TOP__ (description, year?, manufacturer?, biosset*, rom*, disk*, device_ref*, sample*, chip*, display*, sound?, input?, dipswitch*, configuration*, adjuster*, driver?, device*, slot*, softwarelist*, ramoption*)>\n"
+"\t\t<!ATTLIST __XML_TOP__ name CDATA #REQUIRED>\n"
+"\t\t<!ATTLIST __XML_TOP__ sourcefile CDATA #IMPLIED>\n"
+"\t\t<!ATTLIST __XML_TOP__ isbios (yes|no) \"no\">\n"
+"\t\t<!ATTLIST __XML_TOP__ isdevice (yes|no) \"no\">\n"
+"\t\t<!ATTLIST __XML_TOP__ ismechanical (yes|no) \"no\">\n"
+"\t\t<!ATTLIST __XML_TOP__ runnable (yes|no) \"yes\">\n"
+"\t\t<!ATTLIST __XML_TOP__ cloneof CDATA #IMPLIED>\n"
+"\t\t<!ATTLIST __XML_TOP__ romof CDATA #IMPLIED>\n"
+"\t\t<!ATTLIST __XML_TOP__ sampleof CDATA #IMPLIED>\n"
+"\t\t<!ELEMENT description (#PCDATA)>\n"
+"\t\t<!ELEMENT year (#PCDATA)>\n"
+"\t\t<!ELEMENT manufacturer (#PCDATA)>\n"
+"\t\t<!ELEMENT biosset EMPTY>\n"
+"\t\t\t<!ATTLIST biosset name CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST biosset description CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST biosset default (yes|no) \"no\">\n"
+"\t\t<!ELEMENT rom EMPTY>\n"
+"\t\t\t<!ATTLIST rom name CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST rom bios CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST rom size CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST rom crc CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST rom sha1 CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST rom merge CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST rom region CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST rom offset CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST rom status (baddump|nodump|good) \"good\">\n"
+"\t\t\t<!ATTLIST rom optional (yes|no) \"no\">\n"
+"\t\t<!ELEMENT disk EMPTY>\n"
+"\t\t\t<!ATTLIST disk name CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST disk sha1 CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST disk merge CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST disk region CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST disk index CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST disk writable (yes|no) \"no\">\n"
+"\t\t\t<!ATTLIST disk status (baddump|nodump|good) \"good\">\n"
+"\t\t\t<!ATTLIST disk optional (yes|no) \"no\">\n"
+"\t\t<!ELEMENT device_ref EMPTY>\n"
+"\t\t\t<!ATTLIST device_ref name CDATA #REQUIRED>\n"
+"\t\t<!ELEMENT sample EMPTY>\n"
+"\t\t\t<!ATTLIST sample name CDATA #REQUIRED>\n"
+"\t\t<!ELEMENT chip EMPTY>\n"
+"\t\t\t<!ATTLIST chip name CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST chip tag CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST chip type (cpu|audio) #REQUIRED>\n"
+"\t\t\t<!ATTLIST chip clock CDATA #IMPLIED>\n"
+"\t\t<!ELEMENT display EMPTY>\n"
+"\t\t\t<!ATTLIST display tag CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST display type (raster|vector|lcd|unknown) #REQUIRED>\n"
+"\t\t\t<!ATTLIST display rotate (0|90|180|270) #REQUIRED>\n"
+"\t\t\t<!ATTLIST display flipx (yes|no) \"no\">\n"
+"\t\t\t<!ATTLIST display width CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST display height CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST display refresh CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST display pixclock CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST display htotal CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST display hbend CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST display hbstart CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST display vtotal CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST display vbend CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST display vbstart CDATA #IMPLIED>\n"
+"\t\t<!ELEMENT sound EMPTY>\n"
+"\t\t\t<!ATTLIST sound channels CDATA #REQUIRED>\n"
+"\t\t<!ELEMENT input (control*)>\n"
+"\t\t\t<!ATTLIST input service (yes|no) \"no\">\n"
+"\t\t\t<!ATTLIST input tilt (yes|no) \"no\">\n"
+"\t\t\t<!ATTLIST input players CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST input buttons CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST input coins CDATA #IMPLIED>\n"
+"\t\t\t<!ELEMENT control EMPTY>\n"
+"\t\t\t\t<!ATTLIST control type CDATA #REQUIRED>\n"
+"\t\t\t\t<!ATTLIST control minimum CDATA #IMPLIED>\n"
+"\t\t\t\t<!ATTLIST control maximum CDATA #IMPLIED>\n"
+"\t\t\t\t<!ATTLIST control sensitivity CDATA #IMPLIED>\n"
+"\t\t\t\t<!ATTLIST control keydelta CDATA #IMPLIED>\n"
+"\t\t\t\t<!ATTLIST control reverse (yes|no) \"no\">\n"
+"\t\t\t\t<!ATTLIST control ways CDATA #IMPLIED>\n"
+"\t\t\t\t<!ATTLIST control ways2 CDATA #IMPLIED>\n"
+"\t\t\t\t<!ATTLIST control ways3 CDATA #IMPLIED>\n"
+"\t\t<!ELEMENT dipswitch (dipvalue*)>\n"
+"\t\t\t<!ATTLIST dipswitch name CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST dipswitch tag CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST dipswitch mask CDATA #REQUIRED>\n"
+"\t\t\t<!ELEMENT dipvalue EMPTY>\n"
+"\t\t\t\t<!ATTLIST dipvalue name CDATA #REQUIRED>\n"
+"\t\t\t\t<!ATTLIST dipvalue value CDATA #REQUIRED>\n"
+"\t\t\t\t<!ATTLIST dipvalue default (yes|no) \"no\">\n"
+"\t\t<!ELEMENT configuration (confsetting*)>\n"
+"\t\t\t<!ATTLIST configuration name CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST configuration tag CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST configuration mask CDATA #REQUIRED>\n"
+"\t\t\t<!ELEMENT confsetting EMPTY>\n"
+"\t\t\t\t<!ATTLIST confsetting name CDATA #REQUIRED>\n"
+"\t\t\t\t<!ATTLIST confsetting value CDATA #REQUIRED>\n"
+"\t\t\t\t<!ATTLIST confsetting default (yes|no) \"no\">\n"
+"\t\t<!ELEMENT adjuster EMPTY>\n"
+"\t\t\t<!ATTLIST adjuster name CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST adjuster default CDATA #REQUIRED>\n"
+"\t\t<!ELEMENT driver EMPTY>\n"
+"\t\t\t<!ATTLIST driver status (good|imperfect|preliminary) #REQUIRED>\n"
+"\t\t\t<!ATTLIST driver emulation (good|imperfect|preliminary) #REQUIRED>\n"
+"\t\t\t<!ATTLIST driver color (good|imperfect|preliminary) #REQUIRED>\n"
+"\t\t\t<!ATTLIST driver sound (good|imperfect|preliminary) #REQUIRED>\n"
+"\t\t\t<!ATTLIST driver graphic (good|imperfect|preliminary) #REQUIRED>\n"
+"\t\t\t<!ATTLIST driver cocktail (good|imperfect|preliminary) #IMPLIED>\n"
+"\t\t\t<!ATTLIST driver protection (good|imperfect|preliminary) #IMPLIED>\n"
+"\t\t\t<!ATTLIST driver savestate (supported|unsupported) #REQUIRED>\n"
+"\t\t\t<!ATTLIST driver palettesize CDATA #REQUIRED>\n"
+"\t\t<!ELEMENT device (instance*, extension*)>\n"
+"\t\t\t<!ATTLIST device type CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST device tag CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST device mandatory CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST device interface CDATA #IMPLIED>\n"
+"\t\t\t<!ELEMENT instance EMPTY>\n"
+"\t\t\t\t<!ATTLIST instance name CDATA #REQUIRED>\n"
+"\t\t\t\t<!ATTLIST instance briefname CDATA #REQUIRED>\n"
+"\t\t\t<!ELEMENT extension EMPTY>\n"
+"\t\t\t\t<!ATTLIST extension name CDATA #REQUIRED>\n"
+"\t\t<!ELEMENT slot (slotoption*)>\n"
+"\t\t\t<!ATTLIST slot name CDATA #REQUIRED>\n"
+"\t\t\t<!ELEMENT slotoption EMPTY>\n"
+"\t\t\t\t<!ATTLIST slotoption name CDATA #REQUIRED>\n"
+"\t\t\t\t<!ATTLIST slotoption devname CDATA #REQUIRED>\n"
+"\t\t\t\t<!ATTLIST slotoption default (yes|no) \"no\">\n"
+"\t\t<!ELEMENT softwarelist EMPTY>\n"
+"\t\t\t<!ATTLIST softwarelist name CDATA #REQUIRED>\n"
+"\t\t\t<!ATTLIST softwarelist status (original|compatible) #REQUIRED>\n"
+"\t\t\t<!ATTLIST softwarelist filter CDATA #IMPLIED>\n"
+"\t\t<!ELEMENT ramoption (#PCDATA)>\n"
+"\t\t\t<!ATTLIST ramoption default CDATA #IMPLIED>\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, "<?xml version=\"1.0\"?>\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, "</%s>\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<description>%s</description>\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<year>%s</year>\n", xml_normalize_string(driver.year));
+
+ // print the manufacturer information
+ if (driver.manufacturer != NULL)
+ fprintf(m_output, "\t\t<manufacturer>%s</manufacturer>\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</%s>\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<description>%s</description>\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</%s>\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<FPTR> 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<machine_config &>(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<machine_config &>(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<device_ref name=\"%s\"/>\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<biosset");
+ fprintf(m_output, " name=\"%s\"", xml_normalize_string(ROM_GETNAME(rom)));
+ fprintf(m_output, " description=\"%s\"", xml_normalize_string(ROM_GETHASHDATA(rom)));
+ if (ROM_GETBIOSFLAGS(rom) == 1)
+ fprintf(m_output, " default=\"yes\"");
+ fprintf(m_output, "/>\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<rom");
+ else
+ fprintf(m_output, "\t\t<disk");
+
+ // add name, merge, bios, and size tags */
+ if (name != NULL && name[0] != 0)
+ fprintf(m_output, " name=\"%s\"", xml_normalize_string(name));
+ if (merge_name != NULL)
+ fprintf(m_output, " merge=\"%s\"", xml_normalize_string(merge_name));
+ if (bios_name[0] != 0)
+ fprintf(m_output, " bios=\"%s\"", xml_normalize_string(bios_name));
+ if (!is_disk)
+ fprintf(m_output, " size=\"%d\"", rom_file_size(rom));
+
+ // dump checksum information only if there is a known dump
+ if (!hashes.flag(hash_collection::FLAG_NO_DUMP))
+ {
+ // iterate over hash function types and print m_output their values
+ astring tempstr;
+ fprintf(m_output, " %s", hashes.attribute_string(tempstr));
+ }
+ else
+ fprintf(m_output, " status=\"nodump\"");
+
+ // append a region name
+ fprintf(m_output, " region=\"%s\"", ROMREGION_GETTAG(region));
+
+ // for non-disk entries, print offset
+ if (!is_disk)
+ fprintf(m_output, " offset=\"%x\"", offset);
+
+ // for disk entries, add the disk index
+ else
+ {
+ fprintf(m_output, " index=\"%x\"", DISK_GETINDEX(rom));
+ fprintf(m_output, " writable=\"%s\"", DISK_ISREADONLY(rom) ? "no" : "yes");
+ }
+
+ // add optional flag
+ if ((!is_disk && ROM_ISOPTIONAL(rom)) || (is_disk && DISK_ISOPTIONAL(rom)))
+ fprintf(m_output, " optional=\"yes\"");
+
+ fprintf(m_output, "/>\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<int> 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<sample name=\"%s\"/>\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\t<chip");
+ fprintf(m_output, " type=\"cpu\"");
+ fprintf(m_output, " tag=\"%s\"", xml_normalize_string(newtag));
+ fprintf(m_output, " name=\"%s\"", xml_normalize_string(exec->device().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\t<chip");
+ fprintf(m_output, " type=\"audio\"");
+ fprintf(m_output, " tag=\"%s\"", xml_normalize_string(newtag));
+ fprintf(m_output, " name=\"%s\"", xml_normalize_string(sound->device().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\t<display");
+ fprintf(m_output, " tag=\"%s\"", xml_normalize_string(newtag));
+
+ switch (screendev->screen_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<sound channels=\"%d\"/>\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<input");
+ fprintf(m_output, " players=\"%d\"", nplayer);
+ if (nbutton != 0)
+ fprintf(m_output, " buttons=\"%d\"", nbutton);
+ if (ncoin != 0)
+ fprintf(m_output, " coins=\"%d\"", ncoin);
+ if (service)
+ fprintf(m_output, " service=\"yes\"");
+ if (tilt)
+ fprintf(m_output, " tilt=\"yes\"");
+ fprintf(m_output, ">\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<control type=\"%sjoy\"", joys);
+ for (int lp=0; lp<3 && joytype[lp]!=0; lp++)
+ {
+ const char *plural = (lp==2) ? "3" : (lp==1) ? "2" : "";
+ const char *ways;
+ switch (joytype[lp] & (DIR_UP | DIR_DOWN | DIR_LEFT | DIR_RIGHT))
+ {
+ case DIR_UP | DIR_DOWN | DIR_LEFT | DIR_RIGHT:
+ ways = ((joytype[lp] & DIR_4WAY) != 0) ? "4" : "8";
+ break;
+ case DIR_LEFT | DIR_RIGHT:
+ ways = "2";
+ break;
+ case DIR_UP | DIR_DOWN:
+ ways = "vertical2";
+ break;
+ case DIR_UP:
+ case DIR_DOWN:
+ case DIR_LEFT:
+ case DIR_RIGHT:
+ ways = "1";
+ break;
+ case DIR_UP | DIR_DOWN | DIR_LEFT:
+ case DIR_UP | DIR_DOWN | DIR_RIGHT:
+ case DIR_UP | DIR_LEFT | DIR_RIGHT:
+ case DIR_DOWN | DIR_LEFT | DIR_RIGHT:
+ ways = ((joytype[lp] & DIR_4WAY) != 0) ? "3 (half4)" : "5 (half8)";
+ break;
+ default:
+ ways = "strange2";
+ break;
+ }
+ fprintf(m_output, " ways%s=\"%s\"", plural,ways);
+ }
+ fprintf(m_output, "/>\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<control type=\"%s\"", xml_normalize_string(control_info[type].type));
+ if (control_info[type].min != 0 || control_info[type].max != 0)
+ {
+ fprintf(m_output, " minimum=\"%d\"", control_info[type].min);
+ fprintf(m_output, " maximum=\"%d\"", control_info[type].max);
+ }
+ if (control_info[type].sensitivity != 0)
+ fprintf(m_output, " sensitivity=\"%d\"", control_info[type].sensitivity);
+ if (control_info[type].keydelta != 0)
+ fprintf(m_output, " keydelta=\"%d\"", control_info[type].keydelta);
+ if (control_info[type].reverse)
+ fprintf(m_output, " reverse=\"yes\"");
+
+ fprintf(m_output, "/>\n");
+ }
+
+ // output keypad and keyboard
+ if (keypad)
+ fprintf(m_output, "\t\t\t<control type=\"keypad\"/>\n");
+ if (keyboard)
+ fprintf(m_output, "\t\t\t<control type=\"keyboard\"/>\n");
+
+ // misc
+ if (mahjong)
+ fprintf(m_output, "\t\t\t<control type=\"mahjong\"/>\n");
+ if (hanafuda)
+ fprintf(m_output, "\t\t\t<control type=\"hanafuda\"/>\n");
+ if (gambling)
+ fprintf(m_output, "\t\t\t<control type=\"gambling\"/>\n");
+
+ fprintf(m_output, "\t\t</input>\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</%s>\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<adjuster name=\"%s\" default=\"%d\"/>\n", xml_normalize_string(field->name()), field->defvalue());
+}
+
+
+//-------------------------------------------------
+// output_driver - print driver status
+//-------------------------------------------------
+
+void info_xml_creator::output_driver()
+{
+ fprintf(m_output, "\t\t<driver");
+
+ /* The status entry is an hint for frontend authors */
+ /* to select working and not working games without */
+ /* the need to know all the other status entries. */
+ /* Games marked as status=good are perfectly emulated, games */
+ /* marked as status=imperfect are emulated with only */
+ /* some minor issues, games marked as status=preliminary */
+ /* don't work or have major emulation problems. */
+
+ if (m_drivlist.driver().flags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_NO_SOUND | GAME_WRONG_COLORS | GAME_MECHANICAL))
+ fprintf(m_output, " status=\"preliminary\"");
+ else if (m_drivlist.driver().flags & (GAME_IMPERFECT_COLORS | GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS))
+ fprintf(m_output, " status=\"imperfect\"");
+ else
+ fprintf(m_output, " status=\"good\"");
+
+ if (m_drivlist.driver().flags & GAME_NOT_WORKING)
+ fprintf(m_output, " emulation=\"preliminary\"");
+ else
+ fprintf(m_output, " emulation=\"good\"");
+
+ if (m_drivlist.driver().flags & GAME_WRONG_COLORS)
+ fprintf(m_output, " color=\"preliminary\"");
+ else if (m_drivlist.driver().flags & GAME_IMPERFECT_COLORS)
+ fprintf(m_output, " color=\"imperfect\"");
+ else
+ fprintf(m_output, " color=\"good\"");
+
+ if (m_drivlist.driver().flags & GAME_NO_SOUND)
+ fprintf(m_output, " sound=\"preliminary\"");
+ else if (m_drivlist.driver().flags & GAME_IMPERFECT_SOUND)
+ fprintf(m_output, " sound=\"imperfect\"");
+ else
+ fprintf(m_output, " sound=\"good\"");
+
+ if (m_drivlist.driver().flags & GAME_IMPERFECT_GRAPHICS)
+ fprintf(m_output, " graphic=\"imperfect\"");
+ else
+ fprintf(m_output, " graphic=\"good\"");
+
+ if (m_drivlist.driver().flags & GAME_NO_COCKTAIL)
+ fprintf(m_output, " cocktail=\"preliminary\"");
+
+ if (m_drivlist.driver().flags & GAME_UNEMULATED_PROTECTION)
+ fprintf(m_output, " protection=\"preliminary\"");
+
+ if (m_drivlist.driver().flags & GAME_SUPPORTS_SAVE)
+ fprintf(m_output, " savestate=\"supported\"");
+ else
+ fprintf(m_output, " savestate=\"unsupported\"");
+
+ fprintf(m_output, " palettesize=\"%d\"", m_drivlist.config().m_total_colors);
+
+ fprintf(m_output, "/>\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\t<device type=\"%s\"", xml_normalize_string(imagedev->image_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<instance");
+ fprintf(m_output, " name=\"%s\"", xml_normalize_string(name));
+ fprintf(m_output, " briefname=\"%s\"", xml_normalize_string(shortname));
+ fprintf(m_output, "/>\n");
+
+ astring extensions(imagedev->file_extensions());
+
+ char *ext = strtok((char *)extensions.cstr(), ",");
+ while (ext != NULL)
+ {
+ fprintf(m_output, "\t\t\t<extension");
+ fprintf(m_output, " name=\"%s\"", xml_normalize_string(ext));
+ fprintf(m_output, "/>\n");
+ ext = strtok(NULL, ",");
+ }
+
+ fprintf(m_output, "\t\t</device>\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 (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<slot name=\"%s\">\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; i++)
+ {
+ device_t *dev = const_cast<machine_config &>(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\t<slotoption");
+ fprintf(m_output, " name=\"%s\"", xml_normalize_string(intf[i].name));
+ fprintf(m_output, " devname=\"%s\"", xml_normalize_string(dev->shortname()));
+ if (slot->get_default_card(m_drivlist.config(), m_drivlist.options()))
+ {
+ if (strcmp(slot->get_default_card(m_drivlist.config(), m_drivlist.options()),intf[i].name)==0)
+ fprintf(m_output, " default=\"yes\"");
+ }
+ fprintf(m_output, "/>\n");
+ const_cast<machine_config &>(m_drivlist.config()).device_remove(&m_drivlist.config().root_device(), "dummy");
+ }
+
+ fprintf(m_output, "\t\t</slot>\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\t<softwarelist name=\"%s\" ", swlist->list_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<ramoption default=\"1\">%u</ramoption>\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<ramoption>%u</ramoption>\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;
+}