/*************************************************************************** info.c Dumps the MAME internal data as an XML file. Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team. Visit http://mamedev.org for licensing and usage restrictions. ***************************************************************************/ #include #include "driver.h" #include "sound/samples.h" #include "info.h" #include "xmlfile.h" #include "hash.h" /* MESS/MAME configuration */ #ifdef MESS #define XML_ROOT "mess" #define XML_TOP "machine" #else #define XML_ROOT "mame" #define XML_TOP "game" #endif #ifdef MESS void print_game_device(FILE* out, const game_driver* game); void print_game_ramoptions(FILE* out, const game_driver* game); #endif /* MESS */ /* Print a free format string */ static void print_game_switch(FILE* out, const game_driver* game) { const input_port_entry* input; begin_resource_tracking(); input = input_port_allocate(game->ipt, NULL); while (input->type != IPT_END) { if (input->type==IPT_DIPSWITCH_NAME) { int def = input->default_value; fprintf(out, "\t\tname)); ++input; fprintf(out, ">\n"); while (input->type==IPT_DIPSWITCH_SETTING) { fprintf(out, "\t\t\tname)); if (def == input->default_value) fprintf(out, " default=\"yes\""); fprintf(out, "/>\n"); ++input; } fprintf(out, "\t\t\n"); } else ++input; } end_resource_tracking(); } static void print_game_input(FILE* out, const game_driver* game) { enum {cjoy, cdoublejoy, cAD_stick, cdial, ctrackball, cpaddle, clightgun, cpedal, ENDCONTROLTYPES}; const input_port_entry* input; int nplayer = 0; int nbutton = 0; int ncoin = 0; int controlsyes = 0; int analogcontrol = 0; int i; const char* service = 0; const char* tilt = 0; const char* control_types[] = {"joy", "doublejoy", "stick", "dial", "trackball", "paddle", "lightgun", "pedal"}; static struct _input_info { const char * type; /* general type of input */ const char * Xway; /* 2, 4, or 8 way */ int analog; int min; /* analog minimum value */ int max; /* analog maximum value */ int sensitivity; /* default analog sensitivity */ int keydelta; /* default analog keydelta */ int reverse; /* default analog reverse setting */ } control[ENDCONTROLTYPES]; for (i=0;iipt, NULL); while (input->type != IPT_END) { if (nplayer < input->player+1) nplayer = input->player+1; switch (input->type) { case IPT_JOYSTICK_LEFT: case IPT_JOYSTICK_RIGHT: /* if control not defined, start it off as horizontal 2-way */ if (!control[cjoy].Xway) control[cjoy].Xway = "joy2way"; else if (strcmp(control[cjoy].Xway,"joy2way") == 0) ; /* if already defined as vertical, make it 4 or 8 way */ else if (strcmp(control[cjoy].Xway,"vjoy2way") == 0) { if (input->way == 4) control[cjoy].Xway = "joy4way"; else control[cjoy].Xway = "joy8way"; } controlsyes = 1; break; case IPT_JOYSTICK_UP: case IPT_JOYSTICK_DOWN: /* if control not defined, start it off as vertical 2-way */ if (!control[cjoy].Xway) control[cjoy].Xway= "vjoy2way"; else if (strcmp(control[cjoy].Xway,"vjoy2way") == 0) ; /* if already defined as horiz, make it 4 or 8way */ else if (strcmp(control[cjoy].Xway,"joy2way")==0) { if (input->way == 4) control[cjoy].Xway = "joy4way"; else control[cjoy].Xway = "joy8way"; } controlsyes = 1; break; case IPT_JOYSTICKRIGHT_UP: case IPT_JOYSTICKRIGHT_DOWN: case IPT_JOYSTICKLEFT_UP: case IPT_JOYSTICKLEFT_DOWN: /* if control not defined, start it off as vertical 2way */ if (!control[cdoublejoy].Xway) control[cdoublejoy].Xway= "vdoublejoy2way"; else if (strcmp(control[cdoublejoy].Xway,"vdoublejoy2way") == 0) ; /* if already defined as horiz, make it 4 or 8 way */ else if (strcmp(control[cdoublejoy].Xway,"doublejoy2way") == 0) { if (input->way == 4) control[cdoublejoy].Xway = "doublejoy4way"; else control[cdoublejoy].Xway = "doublejoy8way"; } controlsyes = 1; break; case IPT_JOYSTICKRIGHT_LEFT: case IPT_JOYSTICKRIGHT_RIGHT: case IPT_JOYSTICKLEFT_LEFT: case IPT_JOYSTICKLEFT_RIGHT: /* if control not defined, start it off as horiz 2-way */ if (!control[cdoublejoy].Xway) control[cdoublejoy].Xway="doublejoy2way"; else if (strcmp(control[cdoublejoy].Xway,"doublejoy2way") == 0) ; /* if already defined as vertical, make it 4 or 8 way */ else if (strcmp(control[cdoublejoy].Xway,"vdoublejoy2way") == 0) { if (input->way == 4) control[cdoublejoy].Xway = "doublejoy4way"; else control[cdoublejoy].Xway = "doublejoy8way"; } controlsyes = 1; break; /* mark as an analog input, and get analog stats after switch */ case IPT_PADDLE: analogcontrol = cpaddle; break; case IPT_DIAL: analogcontrol = cdial; break; case IPT_TRACKBALL_X: case IPT_TRACKBALL_Y: analogcontrol = ctrackball; break; case IPT_AD_STICK_X: case IPT_AD_STICK_Y: analogcontrol = cAD_stick; break; case IPT_LIGHTGUN_X: case IPT_LIGHTGUN_Y: analogcontrol = clightgun; break; case IPT_PEDAL: case IPT_PEDAL2: case IPT_PEDAL3: analogcontrol = cpedal; break; case IPT_BUTTON1: if (nbutton<1) nbutton = 1; break; case IPT_BUTTON2: if (nbutton<2) nbutton = 2; break; case IPT_BUTTON3: if (nbutton<3) nbutton = 3; break; case IPT_BUTTON4: if (nbutton<4) nbutton = 4; break; case IPT_BUTTON5: if (nbutton<5) nbutton = 5; break; case IPT_BUTTON6: if (nbutton<6) nbutton = 6; break; case IPT_BUTTON7: if (nbutton<7) nbutton = 7; break; case IPT_BUTTON8: if (nbutton<8) nbutton = 8; break; case IPT_BUTTON9: if (nbutton<9) nbutton = 9; break; case IPT_BUTTON10: if (nbutton<10) nbutton = 10; break; case IPT_COIN1: if (ncoin < 1) ncoin = 1; break; case IPT_COIN2: if (ncoin < 2) ncoin = 2; break; case IPT_COIN3: if (ncoin < 3) ncoin = 3; break; case IPT_COIN4: if (ncoin < 4) ncoin = 4; break; case IPT_COIN5: if (ncoin < 5) ncoin = 5; break; case IPT_COIN6: if (ncoin < 6) ncoin = 6; break; case IPT_COIN7: if (ncoin < 7) ncoin = 7; break; case IPT_COIN8: if (ncoin < 8) ncoin = 8; break; case IPT_SERVICE : service = "yes"; break; case IPT_TILT : tilt = "yes"; break; } /* get the analog stats */ if (analogcontrol) { controlsyes = 1; control[analogcontrol].analog = 1; if (input->analog.min) control[analogcontrol].min = input->analog.min; if (input->analog.max) control[analogcontrol].max = input->analog.max; if (input->analog.sensitivity) control[analogcontrol].sensitivity = input->analog.sensitivity; if (input->analog.delta) control[analogcontrol].keydelta = input->analog.delta; if (input->analog.reverse) control[analogcontrol].reverse = 1; analogcontrol = 0; } ++input; } fprintf(out, "\t\t\n"); for (i=0;i\n", xml_normalize_string(control[i].Xway) ); if (control[i].analog) { fprintf(out, "\t\t\t\n"); } } fprintf(out, "\t\t\n"); end_resource_tracking(); } static void print_game_bios(FILE* out, const game_driver* game) { const rom_entry *rom; if (game->rom != NULL) { for (rom = game->rom; !ROMENTRY_ISEND(rom); rom++) if (ROMENTRY_ISSYSTEM_BIOS(rom)) { const char *name = ROM_GETHASHDATA(rom); const char *description = name + strlen(name) + 1; fprintf(out, "\t\t\n"); } } } static void print_game_rom(FILE* out, const game_driver* game) { const rom_entry *region, *rom, *chunk; const rom_entry *pregion, *prom, *fprom=NULL; const game_driver *clone_of; int rom_type; if (!game->rom) return; clone_of = driver_get_clone(game); for (rom_type = 0; rom_type < 3; rom_type++) { for (region = rom_first_region(game); region; region = rom_next_region(region)) for (rom = rom_first_file(region); rom; rom = rom_next_file(rom)) { int offset, length, in_parent, is_disk, is_bios, found_bios, i; char name[100], bios_name[100]; strcpy(name,ROM_GETNAME(rom)); offset = ROM_GETOFFSET(rom); is_disk = ROMREGION_ISDISKDATA(region); is_bios = ROM_GETBIOSFLAGS(rom); switch (rom_type) { case 0: /* rom_type 0 = BIOS */ if (is_disk || !is_bios) continue; break; case 1: /* rom_type 1 = ROM */ if (is_disk || is_bios) continue; break; case 2: /* rom_type 1 = DISK */ if (!is_disk || is_bios) continue; break; } in_parent = 0; length = 0; for (chunk = rom_first_chunk(rom); chunk; chunk = rom_next_chunk(chunk)) length += ROM_GETLENGTH(chunk); if (!ROM_NOGOODDUMP(rom) && clone_of) { fprom=NULL; for (pregion = rom_first_region(clone_of); pregion; pregion = rom_next_region(pregion)) for (prom = rom_first_file(pregion); prom; prom = rom_next_file(prom)) if (hash_data_is_equal(ROM_GETHASHDATA(rom), ROM_GETHASHDATA(prom), 0)) { if (!fprom || !strcmp(ROM_GETNAME(prom), name)) fprom=prom; in_parent = 1; } } found_bios = 0; if(!is_disk && is_bios) { /* Scan backwards for name */ for (prom = rom-1; prom != game->rom; prom--) if (ROMENTRY_ISSYSTEM_BIOS(prom)) { strcpy(bios_name, ROM_GETHASHDATA(prom)); found_bios = 1; break; } } if (!is_disk) fprintf(out, "\t\t\n"); } } } static void print_game_sampleof(FILE* out, const game_driver* game) { #if (HAS_SAMPLES) machine_config drv; int i; expand_machine_driver(game->drv, &drv); for( i = 0; i < MAX_SOUND && drv.sound[i].type != SOUND_DUMMY; i++ ) { const char *const *samplenames = NULL; if( drv.sound[i].type == SOUND_SAMPLES ) samplenames = ((const struct Samplesinterface *)drv.sound[i].config)->samplenames; if (samplenames != 0 && samplenames[0] != 0) { int k = 0; if (samplenames[k][0]=='*') { /* output sampleof only if different from game name */ if (strcmp(samplenames[k] + 1, game->name)!=0) fprintf(out, " sampleof=\"%s\"", xml_normalize_string(samplenames[k] + 1)); ++k; } } } #endif } static void print_game_sample(FILE* out, const game_driver* game) { #if (HAS_SAMPLES) machine_config drv; int i; expand_machine_driver(game->drv, &drv); for( i = 0; i < MAX_SOUND && drv.sound[i].type != SOUND_DUMMY; i++ ) { const char *const *samplenames = NULL; if( drv.sound[i].type == SOUND_SAMPLES ) samplenames = ((const struct Samplesinterface *)drv.sound[i].config)->samplenames; if (samplenames != 0 && samplenames[0] != 0) { int k = 0; if (samplenames[k][0]=='*') { ++k; } while (samplenames[k] != 0) { /* check if is not empty */ if (*samplenames[k]) { /* check if sample is duplicate */ int l = 0; while (l\n", xml_normalize_string(samplenames[k])); } ++k; } } } #endif } static void print_game_micro(FILE* out, const game_driver* game) { machine_config driver; const cpu_config* cpu; const sound_config* sound; int j; expand_machine_driver(game->drv, &driver); cpu = driver.cpu; sound = driver.sound; for(j=0;j\n"); } } for(j=0;j\n"); } } } static void print_game_display(FILE* out, const game_driver* game) { machine_config driver; int dx; int dy; int scrnum; expand_machine_driver(game->drv, &driver); for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++) if (driver.screen[scrnum].tag != NULL) { fprintf(out, "\t\tflags & ORIENTATION_MASK) { case ORIENTATION_FLIP_X: fprintf(out, " rotate=\"0\" flipx=\"yes\""); break; case ORIENTATION_FLIP_Y: fprintf(out, " rotate=\"180\" flipx=\"yes\""); break; case ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y: fprintf(out, " rotate=\"180\""); break; case ORIENTATION_SWAP_XY: fprintf(out, " rotate=\"90\" flipx=\"yes\""); break; case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X: fprintf(out, " rotate=\"90\""); break; case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_Y: fprintf(out, " rotate=\"270\""); break; case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y: fprintf(out, " rotate=\"270\" flipx=\"yes\""); break; default: fprintf(out, " rotate=\"0\""); break; } /* output width and height only for games that are not vector */ if (! (driver.video_attributes & VIDEO_TYPE_VECTOR) ) { dx = driver.screen[scrnum].defstate.visarea.max_x - driver.screen[scrnum].defstate.visarea.min_x + 1; dy = driver.screen[scrnum].defstate.visarea.max_y - driver.screen[scrnum].defstate.visarea.min_y + 1; fprintf(out, " width=\"%d\"", dx); fprintf(out, " height=\"%d\"", dy); } fprintf(out, " refresh=\"%f\"", ATTOSECONDS_TO_HZ(driver.screen[scrnum].defstate.refresh)); fprintf(out, " />\n"); } } static void print_game_sound(FILE* out, const game_driver* game) { machine_config driver; const cpu_config* cpu; const sound_config* sound; /* check if the game have sound emulation */ int has_sound = 0; int i; expand_machine_driver(game->drv, &driver); cpu = driver.cpu; sound = driver.sound; i = 0; while (i < MAX_SOUND && !has_sound) { if (sound[i].type != SOUND_DUMMY) has_sound = 1; ++i; } fprintf(out, "\t\t\n"); } static void print_game_driver(FILE* out, const game_driver* game) { machine_config driver; expand_machine_driver(game->drv, &driver); fprintf(out, "\t\tflags & (GAME_NOT_WORKING | GAME_UNEMULATED_PROTECTION | GAME_NO_SOUND | GAME_WRONG_COLORS)) fprintf(out, " status=\"preliminary\""); else if (game->flags & (GAME_IMPERFECT_COLORS | GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS)) fprintf(out, " status=\"imperfect\""); else fprintf(out, " status=\"good\""); if (game->flags & GAME_NOT_WORKING) fprintf(out, " emulation=\"preliminary\""); else fprintf(out, " emulation=\"good\""); if (game->flags & GAME_WRONG_COLORS) fprintf(out, " color=\"preliminary\""); else if (game->flags & GAME_IMPERFECT_COLORS) fprintf(out, " color=\"imperfect\""); else fprintf(out, " color=\"good\""); if (game->flags & GAME_NO_SOUND) fprintf(out, " sound=\"preliminary\""); else if (game->flags & GAME_IMPERFECT_SOUND) fprintf(out, " sound=\"imperfect\""); else fprintf(out, " sound=\"good\""); if (game->flags & GAME_IMPERFECT_GRAPHICS) fprintf(out, " graphic=\"imperfect\""); else fprintf(out, " graphic=\"good\""); if (game->flags & GAME_NO_COCKTAIL) fprintf(out, " cocktail=\"preliminary\""); if (game->flags & GAME_UNEMULATED_PROTECTION) fprintf(out, " protection=\"preliminary\""); if (game->flags & GAME_SUPPORTS_SAVE) fprintf(out, " savestate=\"supported\""); else fprintf(out, " savestate=\"unsupported\""); fprintf(out, " palettesize=\"%d\"", driver.total_colors); fprintf(out, "/>\n"); } /* Print the MAME info record for a game */ static void print_game_info(FILE* out, const game_driver* game) { const char *start; const game_driver *clone_of; /* No action if not a game */ if (game->flags & GAME_NO_STANDALONE) return; fprintf(out, "\t<" XML_TOP); fprintf(out, " name=\"%s\"", xml_normalize_string(game->name) ); start = strrchr(game->source_file, '/'); if (!start) start = strrchr(game->source_file, '\\'); if (!start) start = game->source_file - 1; fprintf(out, " sourcefile=\"%s\"", xml_normalize_string(start + 1)); if (game->flags & GAME_IS_BIOS_ROOT) fprintf(out, " isbios=\"yes\""); if (game->flags & GAME_NO_STANDALONE) fprintf(out, " runnable=\"no\""); clone_of = driver_get_clone(game); if (clone_of && !(clone_of->flags & GAME_IS_BIOS_ROOT)) fprintf(out, " cloneof=\"%s\"", xml_normalize_string(clone_of->name)); if (clone_of) fprintf(out, " romof=\"%s\"", xml_normalize_string(clone_of->name)); print_game_sampleof(out, game); fprintf(out, ">\n"); if (game->description) fprintf(out, "\t\t%s\n", xml_normalize_string(game->description)); /* print the year only if is a number */ if (game->year && strspn(game->year,"0123456789")==strlen(game->year)) fprintf(out, "\t\t%s\n", xml_normalize_string(game->year) ); if (game->manufacturer) fprintf(out, "\t\t%s\n", xml_normalize_string(game->manufacturer)); print_game_bios(out, game); print_game_rom(out, game); print_game_sample(out, game); print_game_micro(out, game); print_game_display(out, game); print_game_sound(out, game); print_game_input(out, game); print_game_switch(out, game); print_game_driver(out, game); #ifdef MESS print_game_device(out, game); print_game_ramoptions(out, game); #endif fprintf(out, "\t\n"); } static void print_mame_data(FILE* out, const game_driver* const games[], const char *gamename) { int j; /* print games */ for(j=0;games[j];++j) if (mame_strwildcmp(gamename, games[j]->name) == 0) print_game_info(out, games[j]); } /* Print the MAME database in XML format */ void print_mame_xml(FILE* out, const game_driver* const games[], const char *gamename) { fprintf(out, "\n" "\n" "\t\n" "\t\n" #ifdef MESS "\t\n" #else "\t\n" #endif "\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\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\n" "\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" "\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\n" "\t\t\t\n" "\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\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" #ifdef MESS "\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" #endif "]>\n\n" "<" XML_ROOT " build=\"%s\" debug=\"" #ifdef MAME_DEBUG "yes" #else "no" #endif "\">\n", xml_normalize_string(build_version) ); print_mame_data(out, games, gamename); fprintf(out, "\n"); }