mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-29 17:15:40 +00:00
604 lines
14 KiB
C
604 lines
14 KiB
C
#include "model3.h"
|
|
#include "expat.h"
|
|
|
|
enum
|
|
{
|
|
ELEMENT_NONE = 1,
|
|
ELEMENT_GAMELIST,
|
|
ELEMENT_GAME,
|
|
ELEMENT_DESCRIPTION,
|
|
ELEMENT_YEAR,
|
|
ELEMENT_MANUFACTURER,
|
|
ELEMENT_STEP,
|
|
ELEMENT_CROMSIZE,
|
|
ELEMENT_ROM,
|
|
ELEMENT_PATCH,
|
|
ELEMENT_BRIDGE,
|
|
ELEMENT_INPUT,
|
|
};
|
|
|
|
enum
|
|
{
|
|
ATTR_ROM_TYPE = 1,
|
|
ATTR_ROM_NAME,
|
|
ATTR_ROM_SIZE,
|
|
ATTR_ROM_CRC,
|
|
ATTR_ROM_SHA1,
|
|
ATTR_GAME_NAME,
|
|
ATTR_GAME_PARENT,
|
|
ATTR_PATCH_SIZE,
|
|
ATTR_PATCH_ADDRESS,
|
|
ATTR_PATCH_DATA,
|
|
ATTR_INPUT_TYPE,
|
|
ATTR_INPUT_CENTER,
|
|
ATTR_INPUT_MAPPING,
|
|
};
|
|
|
|
static STRING_ID element_id[] =
|
|
{
|
|
{ "gamelist", ELEMENT_GAMELIST },
|
|
{ "game", ELEMENT_GAME },
|
|
{ "description", ELEMENT_DESCRIPTION },
|
|
{ "year", ELEMENT_YEAR },
|
|
{ "manufacturer", ELEMENT_MANUFACTURER },
|
|
{ "step", ELEMENT_STEP },
|
|
{ "cromsize", ELEMENT_CROMSIZE },
|
|
{ "rom", ELEMENT_ROM },
|
|
{ "patch", ELEMENT_PATCH },
|
|
{ "bridge", ELEMENT_BRIDGE },
|
|
{ "input", ELEMENT_INPUT },
|
|
{ "", 0 },
|
|
};
|
|
|
|
static STRING_ID rom_attr_id[] =
|
|
{
|
|
{ "type", ATTR_ROM_TYPE },
|
|
{ "name", ATTR_ROM_NAME },
|
|
{ "size", ATTR_ROM_SIZE },
|
|
{ "crc", ATTR_ROM_CRC },
|
|
{ "sha1", ATTR_ROM_SHA1 },
|
|
{ "", 0 },
|
|
};
|
|
|
|
static STRING_ID game_attr_id[] =
|
|
{
|
|
{ "name", ATTR_GAME_NAME },
|
|
{ "parent", ATTR_GAME_PARENT },
|
|
{ "", 0 },
|
|
};
|
|
|
|
static STRING_ID patch_attr_id[] =
|
|
{
|
|
{ "size", ATTR_PATCH_SIZE },
|
|
{ "address", ATTR_PATCH_ADDRESS },
|
|
{ "data", ATTR_PATCH_DATA },
|
|
{ "", 0 },
|
|
};
|
|
|
|
static STRING_ID input_attr_id[] =
|
|
{
|
|
{ "type", ATTR_INPUT_TYPE },
|
|
{ "center", ATTR_INPUT_CENTER },
|
|
{ "mapping", ATTR_INPUT_MAPPING },
|
|
{ "", 0 },
|
|
};
|
|
|
|
static STRING_ID step_id[] =
|
|
{
|
|
{ "1.0", 0x10 },
|
|
{ "1.5", 0x15 },
|
|
{ "2.0", 0x20 },
|
|
{ "2.1", 0x21 },
|
|
{ "", 0 },
|
|
};
|
|
|
|
static STRING_ID rom_id[] =
|
|
{
|
|
{ "prog0", ROMTYPE_PROG0 },
|
|
{ "prog1", ROMTYPE_PROG1 },
|
|
{ "prog2", ROMTYPE_PROG2 },
|
|
{ "prog3", ROMTYPE_PROG3 },
|
|
{ "crom00", ROMTYPE_CROM00 },
|
|
{ "crom01", ROMTYPE_CROM01 },
|
|
{ "crom02", ROMTYPE_CROM02 },
|
|
{ "crom03", ROMTYPE_CROM03 },
|
|
{ "crom10", ROMTYPE_CROM10 },
|
|
{ "crom11", ROMTYPE_CROM11 },
|
|
{ "crom12", ROMTYPE_CROM12 },
|
|
{ "crom13", ROMTYPE_CROM13 },
|
|
{ "crom20", ROMTYPE_CROM20 },
|
|
{ "crom21", ROMTYPE_CROM21 },
|
|
{ "crom22", ROMTYPE_CROM22 },
|
|
{ "crom23", ROMTYPE_CROM23 },
|
|
{ "crom30", ROMTYPE_CROM30 },
|
|
{ "crom31", ROMTYPE_CROM31 },
|
|
{ "crom32", ROMTYPE_CROM32 },
|
|
{ "crom33", ROMTYPE_CROM33 },
|
|
{ "vrom00", ROMTYPE_VROM00 },
|
|
{ "vrom01", ROMTYPE_VROM01 },
|
|
{ "vrom02", ROMTYPE_VROM02 },
|
|
{ "vrom03", ROMTYPE_VROM03 },
|
|
{ "vrom04", ROMTYPE_VROM04 },
|
|
{ "vrom05", ROMTYPE_VROM05 },
|
|
{ "vrom06", ROMTYPE_VROM06 },
|
|
{ "vrom07", ROMTYPE_VROM07 },
|
|
{ "vrom10", ROMTYPE_VROM10 },
|
|
{ "vrom11", ROMTYPE_VROM11 },
|
|
{ "vrom12", ROMTYPE_VROM12 },
|
|
{ "vrom13", ROMTYPE_VROM13 },
|
|
{ "vrom14", ROMTYPE_VROM14 },
|
|
{ "vrom15", ROMTYPE_VROM15 },
|
|
{ "vrom16", ROMTYPE_VROM16 },
|
|
{ "vrom17", ROMTYPE_VROM17 },
|
|
{ "sprog", ROMTYPE_SPROG },
|
|
{ "srom0", ROMTYPE_SROM0 },
|
|
{ "srom1", ROMTYPE_SROM1 },
|
|
{ "srom2", ROMTYPE_SROM2 },
|
|
{ "srom3", ROMTYPE_SROM3 },
|
|
{ "dsbprog", ROMTYPE_DSBPROG },
|
|
{ "dsbrom0", ROMTYPE_DSBROM0 },
|
|
{ "dsbrom1", ROMTYPE_DSBROM1 },
|
|
{ "dsbrom2", ROMTYPE_DSBROM2 },
|
|
{ "dsbrom3", ROMTYPE_DSBROM3 },
|
|
{ "", 0 },
|
|
};
|
|
|
|
#define INPUT_TYPE_BUTTON 0x10000
|
|
#define INPUT_TYPE_ANALOG 0x20000
|
|
|
|
static STRING_ID input_id[] =
|
|
{
|
|
{ "button01", INPUT_TYPE_BUTTON | 0 },
|
|
{ "button02", INPUT_TYPE_BUTTON | 1 },
|
|
{ "button03", INPUT_TYPE_BUTTON | 2 },
|
|
{ "button04", INPUT_TYPE_BUTTON | 3 },
|
|
{ "button05", INPUT_TYPE_BUTTON | 4 },
|
|
{ "button06", INPUT_TYPE_BUTTON | 5 },
|
|
{ "button07", INPUT_TYPE_BUTTON | 6 },
|
|
{ "button08", INPUT_TYPE_BUTTON | 7 },
|
|
{ "button11", INPUT_TYPE_BUTTON | 8 },
|
|
{ "button12", INPUT_TYPE_BUTTON | 9 },
|
|
{ "button13", INPUT_TYPE_BUTTON | 10 },
|
|
{ "button14", INPUT_TYPE_BUTTON | 11 },
|
|
{ "button15", INPUT_TYPE_BUTTON | 12 },
|
|
{ "button16", INPUT_TYPE_BUTTON | 13 },
|
|
{ "button17", INPUT_TYPE_BUTTON | 14 },
|
|
{ "button18", INPUT_TYPE_BUTTON | 15 },
|
|
{ "analog1", INPUT_TYPE_ANALOG | 0 },
|
|
{ "analog2", INPUT_TYPE_ANALOG | 1 },
|
|
{ "analog3", INPUT_TYPE_ANALOG | 2 },
|
|
{ "analog4", INPUT_TYPE_ANALOG | 3 },
|
|
{ "analog5", INPUT_TYPE_ANALOG | 4 },
|
|
{ "analog6", INPUT_TYPE_ANALOG | 5 },
|
|
{ "analog7", INPUT_TYPE_ANALOG | 6 },
|
|
{ "analog8", INPUT_TYPE_ANALOG | 7 },
|
|
{ "", 0 },
|
|
};
|
|
|
|
static STRING_ID input_mapping_id[] =
|
|
{
|
|
{ "p1_button_1", P1_BUTTON_1 },
|
|
{ "p1_button_2", P1_BUTTON_2 },
|
|
{ "p1_button_3", P1_BUTTON_3 },
|
|
{ "p1_button_4", P1_BUTTON_4 },
|
|
{ "p1_button_5", P1_BUTTON_5 },
|
|
{ "p1_button_6", P1_BUTTON_6 },
|
|
{ "p1_button_7", P1_BUTTON_7 },
|
|
{ "p1_button_8", P1_BUTTON_8 },
|
|
{ "p2_button_1", P2_BUTTON_1 },
|
|
{ "p2_button_2", P2_BUTTON_2 },
|
|
{ "p2_button_3", P2_BUTTON_3 },
|
|
{ "p2_button_4", P2_BUTTON_4 },
|
|
{ "p2_button_5", P2_BUTTON_5 },
|
|
{ "p2_button_6", P2_BUTTON_6 },
|
|
{ "p2_button_7", P2_BUTTON_7 },
|
|
{ "p2_button_8", P2_BUTTON_8 },
|
|
{ "analog_axis_1", ANALOG_AXIS_1 },
|
|
{ "analog_axis_2", ANALOG_AXIS_2 },
|
|
{ "analog_axis_3", ANALOG_AXIS_3 },
|
|
{ "analog_axis_4", ANALOG_AXIS_4 },
|
|
{ "analog_axis_5", ANALOG_AXIS_5 },
|
|
{ "analog_axis_6", ANALOG_AXIS_6 },
|
|
{ "analog_axis_7", ANALOG_AXIS_7 },
|
|
{ "analog_axis_8", ANALOG_AXIS_8 },
|
|
{ "p1_joystick_up", P1_JOYSTICK_UP },
|
|
{ "p1_joystick_down", P1_JOYSTICK_DOWN },
|
|
{ "p1_joystick_left", P1_JOYSTICK_LEFT },
|
|
{ "p1_joystick_right", P1_JOYSTICK_RIGHT },
|
|
{ "p2_joystick_up", P2_JOYSTICK_UP },
|
|
{ "p2_joystick_down", P2_JOYSTICK_DOWN },
|
|
{ "p2_joystick_left", P2_JOYSTICK_LEFT },
|
|
{ "p2_joystick_right", P2_JOYSTICK_RIGHT },
|
|
{ "", 0 },
|
|
};
|
|
|
|
|
|
|
|
static UINT8 *romlist;
|
|
|
|
static ROMSET *romset;
|
|
|
|
static int current_attr;
|
|
static int current_element;
|
|
|
|
static int current_rom;
|
|
static int current_romset;
|
|
static int current_patch;
|
|
static int current_input;
|
|
|
|
|
|
|
|
static void XMLCALL element_start(void *data, const char *el, const char **attr)
|
|
{
|
|
int element = get_string_id(el, element_id);
|
|
|
|
if (element < 0)
|
|
{
|
|
message(0, "Unknown element %s while parsing XML file\n", el);
|
|
}
|
|
else
|
|
{
|
|
current_element = element;
|
|
|
|
switch (element)
|
|
{
|
|
case ELEMENT_ROM:
|
|
{
|
|
int i=0;
|
|
|
|
// handle ROM types
|
|
while (attr[i] != NULL)
|
|
{
|
|
int id = get_string_id(attr[i], rom_attr_id);
|
|
|
|
if (id >= 0)
|
|
{
|
|
current_attr = id;
|
|
}
|
|
else
|
|
{
|
|
// not a type
|
|
switch (current_attr)
|
|
{
|
|
case ATTR_ROM_TYPE:
|
|
{
|
|
int romtype = get_string_id(attr[i], rom_id);
|
|
romset[current_romset].rom[current_rom].type = romtype;
|
|
break;
|
|
}
|
|
case ATTR_ROM_NAME:
|
|
{
|
|
strcpy(romset[current_romset].rom[current_rom].name, attr[i]);
|
|
break;
|
|
}
|
|
case ATTR_ROM_SIZE:
|
|
{
|
|
int romsize;
|
|
sscanf(attr[i], "%d", &romsize);
|
|
romset[current_romset].rom[current_rom].size = romsize;
|
|
break;
|
|
}
|
|
case ATTR_ROM_CRC:
|
|
{
|
|
UINT32 romcrc;
|
|
sscanf(attr[i], "%X", &romcrc);
|
|
romset[current_romset].rom[current_rom].crc32 = romcrc;
|
|
break;
|
|
}
|
|
case ATTR_ROM_SHA1:
|
|
{
|
|
// not handled
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
};
|
|
break;
|
|
}
|
|
|
|
case ELEMENT_GAME:
|
|
{
|
|
int i=0;
|
|
|
|
while (attr[i] != NULL)
|
|
{
|
|
int id = get_string_id(attr[i], game_attr_id);
|
|
|
|
if (id >= 0)
|
|
{
|
|
current_attr = id;
|
|
}
|
|
else
|
|
{
|
|
switch (current_attr)
|
|
{
|
|
case ATTR_GAME_NAME:
|
|
{
|
|
strcpy(romset[current_romset].game, attr[i]);
|
|
break;
|
|
}
|
|
case ATTR_GAME_PARENT:
|
|
{
|
|
strcpy(romset[current_romset].parent, attr[i]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
};
|
|
break;
|
|
}
|
|
|
|
case ELEMENT_PATCH:
|
|
{
|
|
int i=0;
|
|
|
|
while (attr[i] != NULL)
|
|
{
|
|
int id = get_string_id(attr[i], patch_attr_id);
|
|
|
|
if (id >= 0)
|
|
{
|
|
current_attr = id;
|
|
}
|
|
else
|
|
{
|
|
switch (current_attr)
|
|
{
|
|
case ATTR_PATCH_SIZE:
|
|
{
|
|
int patch_size;
|
|
sscanf(attr[i], "%d", &patch_size);
|
|
romset[current_romset].patch[current_patch].size = patch_size;
|
|
break;
|
|
}
|
|
case ATTR_PATCH_ADDRESS:
|
|
{
|
|
UINT32 address;
|
|
sscanf(attr[i], "%X", &address);
|
|
romset[current_romset].patch[current_patch].address = address;
|
|
break;
|
|
}
|
|
case ATTR_PATCH_DATA:
|
|
{
|
|
UINT32 data;
|
|
sscanf(attr[i], "%X", &data);
|
|
romset[current_romset].patch[current_patch].data = data;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
};
|
|
break;
|
|
}
|
|
|
|
case ELEMENT_INPUT:
|
|
{
|
|
int i=0;
|
|
|
|
while (attr[i] != NULL)
|
|
{
|
|
int id = get_string_id(attr[i], input_attr_id);
|
|
|
|
if (id >= 0)
|
|
{
|
|
current_attr = id;
|
|
}
|
|
else
|
|
{
|
|
switch (current_attr)
|
|
{
|
|
case ATTR_INPUT_TYPE:
|
|
{
|
|
current_input = get_string_id(attr[i], input_id);
|
|
|
|
if (current_input & INPUT_TYPE_BUTTON)
|
|
{
|
|
int button = current_input & 0xffff;
|
|
int set = (button / 8) & 1;
|
|
int bit = 1 << (button % 8);
|
|
romset[current_romset].controls.button[button].enabled = 1;
|
|
romset[current_romset].controls.button[button].control_set = set;
|
|
romset[current_romset].controls.button[button].control_bit = bit;
|
|
}
|
|
else if (current_input & INPUT_TYPE_ANALOG)
|
|
{
|
|
int axis = current_input & 0xffff;
|
|
romset[current_romset].controls.analog_axis[axis].enabled = 1;
|
|
}
|
|
break;
|
|
}
|
|
case ATTR_INPUT_CENTER:
|
|
{
|
|
if (current_input & INPUT_TYPE_ANALOG)
|
|
{
|
|
int axis = current_input & 0xffff;
|
|
int center;
|
|
sscanf(attr[i], "%d", ¢er);
|
|
romset[current_romset].controls.analog_axis[axis].center = center;
|
|
}
|
|
break;
|
|
}
|
|
case ATTR_INPUT_MAPPING:
|
|
{
|
|
int mapping = get_string_id(attr[i], input_mapping_id);
|
|
if (current_input & INPUT_TYPE_BUTTON)
|
|
{
|
|
int button = current_input & 0xffff;
|
|
romset[current_romset].controls.button[button].mapping = mapping;
|
|
}
|
|
else if (current_input & INPUT_TYPE_ANALOG)
|
|
{
|
|
int axis = current_input & 0xffff;
|
|
romset[current_romset].controls.analog_axis[axis].mapping = mapping;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void XMLCALL element_end(void *data, const char *el)
|
|
{
|
|
int element = get_string_id(el, element_id);
|
|
|
|
if (element < 0)
|
|
{
|
|
message(0, "Unknown element %s while parsing XML\n", el);
|
|
}
|
|
else
|
|
{
|
|
switch (element)
|
|
{
|
|
case ELEMENT_ROM:
|
|
{
|
|
current_rom++;
|
|
current_element = ELEMENT_GAMELIST;
|
|
break;
|
|
}
|
|
case ELEMENT_GAME:
|
|
{
|
|
romset[current_romset].num_patches = current_patch;
|
|
current_romset++;
|
|
current_rom = 0;
|
|
current_patch = 0;
|
|
current_element = ELEMENT_GAMELIST;
|
|
break;
|
|
}
|
|
case ELEMENT_DESCRIPTION:
|
|
case ELEMENT_YEAR:
|
|
case ELEMENT_MANUFACTURER:
|
|
case ELEMENT_STEP:
|
|
case ELEMENT_BRIDGE:
|
|
case ELEMENT_CROMSIZE:
|
|
{
|
|
current_element = ELEMENT_GAMELIST;
|
|
break;
|
|
}
|
|
case ELEMENT_PATCH:
|
|
{
|
|
current_patch++;
|
|
current_element = ELEMENT_GAMELIST;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void XMLCALL character_data(void *data, const char *s, int len)
|
|
{
|
|
char temp[2000];
|
|
memcpy(temp, s, len);
|
|
temp[len] = 0;
|
|
|
|
switch (current_element)
|
|
{
|
|
case ELEMENT_DESCRIPTION:
|
|
{
|
|
strcpy(romset[current_romset].title, temp);
|
|
break;
|
|
}
|
|
case ELEMENT_YEAR:
|
|
{
|
|
int year;
|
|
sscanf(temp, "%d", &year);
|
|
romset[current_romset].year = year;
|
|
break;
|
|
}
|
|
case ELEMENT_MANUFACTURER:
|
|
{
|
|
strcpy(romset[current_romset].manufacturer, temp);
|
|
break;
|
|
}
|
|
case ELEMENT_STEP:
|
|
{
|
|
int step = get_string_id(temp, step_id);
|
|
|
|
if (step >= 0)
|
|
{
|
|
romset[current_romset].step = step;
|
|
}
|
|
else
|
|
{
|
|
message(0, "Invalid step %s while parsing XML file\n", temp);
|
|
}
|
|
break;
|
|
}
|
|
case ELEMENT_BRIDGE:
|
|
{
|
|
if (_stricmp(temp, "mpc106") == 0)
|
|
{
|
|
romset[current_romset].bridge = 2;
|
|
}
|
|
else
|
|
{
|
|
message(0, "Unknown bridge %s while parsing XML file\n", temp);
|
|
}
|
|
break;
|
|
}
|
|
case ELEMENT_CROMSIZE:
|
|
{
|
|
if (_stricmp(temp, "64M") == 0)
|
|
{
|
|
romset[current_romset].cromsize = 1;
|
|
}
|
|
else
|
|
{
|
|
message(0, "Unknown cromsize %s while parsing XML file\n", temp);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int parse_romlist(char *romlist_name, ROMSET *_romset)
|
|
{
|
|
XML_Parser parser;
|
|
|
|
int length;
|
|
FILE *file;
|
|
|
|
file = open_file(FILE_READ|FILE_BINARY, "%s", romlist_name);
|
|
if (file == NULL)
|
|
{
|
|
message(0, "Couldn't open %s", romlist_name);
|
|
return 0;
|
|
}
|
|
|
|
length = (int)get_open_file_size(file);
|
|
|
|
romlist = (UINT8*)malloc(length);
|
|
|
|
if (!read_from_file(file, romlist, length))
|
|
{
|
|
message(0, "I/O error while reading %s", romlist_name);
|
|
return 0;
|
|
}
|
|
|
|
close_file(file);
|
|
|
|
romset = _romset;
|
|
|
|
// parse the XML file
|
|
parser = XML_ParserCreate(NULL);
|
|
|
|
XML_SetElementHandler(parser, element_start, element_end);
|
|
XML_SetCharacterDataHandler(parser, character_data);
|
|
|
|
if (XML_Parse(parser, romlist, length, 1) != XML_STATUS_OK)
|
|
{
|
|
message(0, "Error while parsing the XML file %s", romlist_name);
|
|
return 0;
|
|
}
|
|
|
|
XML_ParserFree(parser);
|
|
return current_romset;
|
|
} |