Removed last vestiges of CINIFile from input system and removed Games.cpp, INIFile.cpp, and ROMLoad.cpp

This commit is contained in:
Bart Trzynadlowski 2017-04-05 16:19:08 +00:00
parent df283d9aa3
commit cc32e0bf8e
18 changed files with 21 additions and 5141 deletions

View file

@ -88,8 +88,8 @@ endif
# Objects and Dependencies
#
HEADERS = Src/Supermodel.h Src/Games.h Src/OSD/SDL/Types.h
OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/Games.o $(OBJ_DIR)/Config.o $(OBJ_DIR)/INIFile.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
$(OBJ_DIR)/ROMLoad.o $(OBJ_DIR)/unzip.o $(OBJ_DIR)/ioapi.o $(OBJ_DIR)/Error.o $(OBJ_DIR)/glew.o $(OBJ_DIR)/Shader.o \
OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
$(OBJ_DIR)/unzip.o $(OBJ_DIR)/ioapi.o $(OBJ_DIR)/Error.o $(OBJ_DIR)/glew.o $(OBJ_DIR)/Shader.o \
$(OBJ_DIR)/Real3D.o $(OBJ_DIR)/Legacy3D.o $(OBJ_DIR)/Models.o $(OBJ_DIR)/TextureRefs.o \
$(OBJ_DIR)/New3D.o $(OBJ_DIR)/Mat4.o $(OBJ_DIR)/Model.o $(OBJ_DIR)/PolyHeader.o $(OBJ_DIR)/Texture.o $(OBJ_DIR)/TextureSheet.o $(OBJ_DIR)/VBO.o $(OBJ_DIR)/Vec.o $(OBJ_DIR)/R3DShader.o $(OBJ_DIR)/R3DFloat.o \
$(OBJ_DIR)/Render2D.o $(OBJ_DIR)/TileGen.o \

View file

@ -95,8 +95,8 @@ endif
# Objects and Dependencies
#
HEADERS = Src/Supermodel.h Src/Games.h Src/OSD/SDL/Types.h
OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/Games.o $(OBJ_DIR)/Config.o $(OBJ_DIR)/INIFile.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
$(OBJ_DIR)/ROMLoad.o $(OBJ_DIR)/unzip.o $(OBJ_DIR)/ioapi.o $(OBJ_DIR)/Error.o $(OBJ_DIR)/glew.o $(OBJ_DIR)/Shader.o \
OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
$(OBJ_DIR)/unzip.o $(OBJ_DIR)/ioapi.o $(OBJ_DIR)/Error.o $(OBJ_DIR)/glew.o $(OBJ_DIR)/Shader.o \
$(OBJ_DIR)/Real3D.o $(OBJ_DIR)/Legacy3D.o $(OBJ_DIR)/Models.o $(OBJ_DIR)/TextureRefs.o \
$(OBJ_DIR)/New3D.o $(OBJ_DIR)/Mat4.o $(OBJ_DIR)/Model.o $(OBJ_DIR)/PolyHeader.o $(OBJ_DIR)/Texture.o $(OBJ_DIR)/TextureSheet.o $(OBJ_DIR)/VBO.o $(OBJ_DIR)/Vec.o $(OBJ_DIR)/R3DShader.o $(OBJ_DIR)/R3DFloat.o \
$(OBJ_DIR)/Render2D.o $(OBJ_DIR)/TileGen.o \

View file

@ -119,8 +119,8 @@ endif
#
# Objects and Dependencies
#
OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/Games.o $(OBJ_DIR)/INIFile.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
$(OBJ_DIR)/ROMLoad.o $(OBJ_DIR)/unzip.o $(OBJ_DIR)/ioapi.o $(OBJ_DIR)/Error.o $(OBJ_DIR)/glew.o $(OBJ_DIR)/Shader.o \
OBJ = $(OBJ_DIR)/PPCDisasm.o $(OBJ_DIR)/BlockFile.o $(OBJ_DIR)/93C46.o \
$(OBJ_DIR)/unzip.o $(OBJ_DIR)/ioapi.o $(OBJ_DIR)/Error.o $(OBJ_DIR)/glew.o $(OBJ_DIR)/Shader.o \
$(OBJ_DIR)/Real3D.o $(OBJ_DIR)/Legacy3D.o $(OBJ_DIR)/Models.o $(OBJ_DIR)/TextureRefs.o \
$(OBJ_DIR)/New3D.o $(OBJ_DIR)/Mat4.o $(OBJ_DIR)/Model.o $(OBJ_DIR)/PolyHeader.o $(OBJ_DIR)/Texture.o $(OBJ_DIR)/TextureSheet.o $(OBJ_DIR)/VBO.o $(OBJ_DIR)/Vec.o $(OBJ_DIR)/R3DShader.o $(OBJ_DIR)/R3DFloat.o \
$(OBJ_DIR)/R3DScrollFog.o \

File diff suppressed because it is too large Load diff

View file

@ -1,109 +0,0 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski, Nik Henson
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* Games.h
*
* Header file containing Model 3 game and ROM file information.
*/
#ifndef INCLUDED_GAMES_H
#define INCLUDED_GAMES_H
#include "ROMLoad.h" // ROMInfo structure
/******************************************************************************
Definitions
******************************************************************************/
// Input flags
#define GAME_INPUT_COMMON 0x000000001 // game has common controls
#define GAME_INPUT_VEHICLE 0x000000002 // game has vehicle controls
#define GAME_INPUT_JOYSTICK1 0x000000004 // game has joystick 1
#define GAME_INPUT_JOYSTICK2 0x000000008 // game has joystick 2
#define GAME_INPUT_FIGHTING 0x000000010 // game has fighting game controls
#define GAME_INPUT_VR4 0x000000020 // game has four VR view buttons
#define GAME_INPUT_VIEWCHANGE 0x000000040 // game has single view change button
#define GAME_INPUT_SHIFT4 0x000000080 // game has 4-speed shifter
#define GAME_INPUT_SHIFTUPDOWN 0x000000100 // game has up/down shifter
#define GAME_INPUT_HANDBRAKE 0x000000200 // game has handbrake
#define GAME_INPUT_HARLEY 0x000000400 // game has Harley Davidson controls
#define GAME_INPUT_GUN1 0x000000800 // game has light gun 1
#define GAME_INPUT_GUN2 0x000001000 // game has light gun 2
#define GAME_INPUT_ANALOG_JOYSTICK 0x000002000 // game has analog joystick
#define GAME_INPUT_TWIN_JOYSTICKS 0x000004000 // game has twin joysticks
#define GAME_INPUT_SOCCER 0x000008000 // game has soccer controls
#define GAME_INPUT_SPIKEOUT 0x000010000 // game has Spikeout buttons
#define GAME_INPUT_ANALOG_GUN1 0x000020000 // game has analog gun 1
#define GAME_INPUT_ANALOG_GUN2 0x000040000 // game has analog gun 2
#define GAME_INPUT_SKI 0x000080000 // game has ski controls
#define GAME_INPUT_MAGTRUCK 0x000100000 // game has magical truck controls
#define GAME_INPUT_FISHING 0x000200000 // game has fishing controls
#define GAME_INPUT_ALL 0x0003FFFFF
/******************************************************************************
Data Structures
******************************************************************************/
/*
* GameInfo:
*
* Describes a Model 3 game. List is terminated when title == NULL.
*/
struct GameInfo
{
// Game information
const char id[10]; // 9-character game identifier (also serves as zip archive file name)
const char *parent; // parent game identifier
const char *title; // complete game title
const char *mfgName; // name of manufacturer
unsigned year; // year released (in decimal)
int step; // Model 3 hardware stepping: 0x10 = 1.0, 0x15 = 1.5, 0x20 = 2.0, 0x21 = 2.1
uint32_t cromSize; // size of fixed CROM (up to 8 MB)
bool mirrorLow64MB; // mirror low 64 MB of banked CROM space to upper 64 MB
uint32_t vromSize; // size of video ROMs (32 or 64 MB; if 32 MB, will have to be mirrored)
uint32_t sampleSize; // size of sample ROMS (8 or 16 MB; if 8 MB, will have to be mirrored)
uint32_t inputFlags; // game input types
int mpegBoard; // MPEG music board type: 0 = none, 1 = DSB1 (Z80), 2 = DSB2 (68K).
bool driveBoard; // drive board (supported if true)
uint32_t encryptionKey; // security board encryption device key (or 0 if not applicable)
// ROM files
struct ROMInfo ROM[48];
};
/******************************************************************************
Model 3 Game List
All games supported by Supermodel. All ROMs are loaded according to their
native endianness. That is, the PowerPC ROMs are loaded just as a real
PowerPC would see them. The emulator may reorder the bytes on its own for
performance reasons (but the ROMs are not specified that way here).
******************************************************************************/
extern const struct GameInfo g_Model3GameList[];
#endif // INCLUDED_GAMES_H

View file

@ -1,704 +0,0 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski, Nik Henson
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* INIFile.cpp
*
* INI file management. Implementation of the CINIFile class.
*
* To-Do List
* ----------
* - Add an iterator to retrieve all settings associated with a given section.
* This will allow detection of invalid setting names, if the caller desires.
* - Add boolean on/off, true/false keywords.
* - Note that linePtr does not necessarily correspond to actual lines in the
* file (newlines should be counted by the tokenizer for that).
*
* Grammar
* -------
*
* Section: '[' Identifier ']'
* Line: Identifier '=' Argument
* Argument: Number
* String
*
* Overview
* --------
* INI files are linear in nature, divided into sections. Each section has
* settings associated with it which may be either numerical values or strings.
* Presently, only unsigned 32-bit integers are supported.
*
* INI files are first opened, then parsed, and finally closed. The parse tree
* is cleared only during object construction and when the INI file is closed.
* Default settings may be inserted before a file is opened or parsed. When an
* INI file is written out, the current INI file on the disk is cleared. If an
* error occurs during this process, the data will be lost.
*
* Sections are added only when a setting is found in that section. Empty
* sections are not added to the tree with the exception of the default ("")
* section. A default section name can be specified, which creates an alias
* for the default section. The alias will be output when the file is
* written (there will be no settings without an explicit section).
*/
#include "Supermodel.h"
using namespace std;
/******************************************************************************
Basic Functions
******************************************************************************/
bool CINIFile::Write(const char *comment)
{
bool writeSuccess;
// In order to truncate, we must close and reopen as truncated
File.close();
File.clear(); // required to clear EOF flag (open() does not clear)
File.open(FileName.c_str(),fstream::out|fstream::trunc);
if (File.fail())
{
return FAIL;
}
// Output comment
if (comment != NULL)
File << comment << endl;
// Iterate through all sections sequentially
for (unsigned i = 0; i < Sections.size(); i++)
{
if (Sections[i].Settings.size() != 0)
{
// Output section name
if (Sections[i].Name != "")
File << "[ " << Sections[i].Name << " ]" << endl << endl;
else // if null name, use default section name (if exists) or nothing at all
{
if (DefaultSectionName != "")
File << "[ " << DefaultSectionName << " ]" << endl << endl;
}
// Iterate through all settings within this section
for (unsigned j = 0; j < Sections[i].Settings.size(); j++)
{
// Output setting
File << Sections[i].Settings[j].Name << " = ";
if (Sections[i].Settings[j].isNumber)
File << Sections[i].Settings[j].value << endl;
else
File << '\"' << Sections[i].Settings[j].String << '\"' << endl;
}
// New line
File << endl;
}
}
writeSuccess = File.good()?OKAY:FAIL;
// Close and reopen as read/write
File.close();
File.open(FileName.c_str(),fstream::in|fstream::out);
if (File.fail())
{
//printf("unable to re-open %s for reading/writing\n", FileName.c_str());
return FAIL;
}
// Report any errors that occurred during writing
return writeSuccess;
}
bool CINIFile::Open(const char *fileNameStr)
{
FileName = fileNameStr;
// Try to open for reading AND writing
File.open(fileNameStr, fstream::in|fstream::out);
if (File.fail())
return FAIL;
InitParseTree();
return OKAY;
}
bool CINIFile::OpenAndCreate(const char *fileNameStr)
{
FileName = fileNameStr;
// Try to open for reading and writing
File.open(fileNameStr, fstream::in|fstream::out);
if (File.fail())
{
// File does not exist, try opening as write only (create it)
File.clear();
File.open(fileNameStr, fstream::out);
if (File.fail())
return FAIL;
}
InitParseTree();
return OKAY;
}
void CINIFile::Close(void)
{
File.close();
Sections.clear(); // clear the parse tree!
}
/******************************************************************************
Management of Settings
******************************************************************************/
// Finds index of first matching section in the section list. Returns FAIL if not found.
bool CINIFile::LookUpSection(unsigned *idx, string SectionName)
{
for (unsigned i = 0; i < Sections.size(); i++)
{
if ((Sections[i].Name == SectionName) ||
((Sections[i].Name == "") && (SectionName == DefaultSectionName)) || // if default section, also accept its alias
((Sections[i].Name == DefaultSectionName) && (SectionName == ""))) // ...
{
*idx = i;
return OKAY;
}
}
return FAIL;
}
// Assigns a value to the given setting, creating the setting if it does not exist. Nulls out the string (sets it to "").
void CINIFile::Set(string SectionName, string SettingName, int value)
{
struct Setting NewSetting;
unsigned sectionIdx, settingIdx;
// Check if the section exists anywhere in parse tree. If not, create it
if (OKAY != LookUpSection(&sectionIdx, SectionName))
{
//printf("unable to find %s:%s, creating section\n", SectionName.c_str(), SettingName.c_str());
struct Section NewSection;
NewSection.Name = SectionName;
Sections.push_back(NewSection);
sectionIdx = Sections.size()-1; // the new section will be at the last index
}
// Search through all sections with the requested name for the first occurance of the desired setting
for (unsigned i = 0; i < Sections.size(); i++)
{
if ((Sections[i].Name == SectionName) ||
((Sections[i].Name == "") && (SectionName == DefaultSectionName)) || // accept alias for default section
((Sections[i].Name == DefaultSectionName) && (SectionName == ""))) // ...
{
for (unsigned j = 0; j < Sections[i].Settings.size(); j++)
{
if (Sections[i].Settings[j].Name == SettingName)
{
// Found it! Update value of this setting
sectionIdx = i;
settingIdx = j;
goto UpdateIntValue;
}
}
}
}
// Couldn't find setting, create it in the first matching section found earlier
NewSetting.Name = SettingName;
Sections[sectionIdx].Settings.push_back(NewSetting);
settingIdx = Sections[sectionIdx].Settings.size()-1;
// Update the setting!
UpdateIntValue:
Sections[sectionIdx].Settings[settingIdx].isNumber = true;
Sections[sectionIdx].Settings[settingIdx].value = value;
Sections[sectionIdx].Settings[settingIdx].String = "";
}
// Assigns the string to the given setting, creating the setting if it does not exist. Zeros out the value.
void CINIFile::Set(string SectionName, string SettingName, string String)
{
struct Setting NewSetting;
unsigned sectionIdx, settingIdx;
// Check if the section exists anywhere in parse tree. If not, create it
if (OKAY != LookUpSection(&sectionIdx, SectionName))
{
//printf("unable to find %s:%s, creating section\n", SectionName.c_str(), SettingName.c_str());
struct Section NewSection;
NewSection.Name = SectionName;
Sections.push_back(NewSection);
sectionIdx = Sections.size()-1; // the new section will be at the last index
}
// Search through all sections with the requested name for the first occurance of the desired setting
for (unsigned i = 0; i < Sections.size(); i++)
{
if ((Sections[i].Name == SectionName) ||
((Sections[i].Name == "") && (SectionName == DefaultSectionName)) || // accept alias for default section
((Sections[i].Name == DefaultSectionName) && (SectionName == ""))) // ...
{
for (unsigned j = 0; j < Sections[i].Settings.size(); j++)
{
if (Sections[i].Settings[j].Name == SettingName)
{
// Found it! Update value of this setting
sectionIdx = i;
settingIdx = j;
goto UpdateString;
}
}
}
}
// Couldn't find setting, create it in the first matching section found earlier
NewSetting.Name = SettingName;
Sections[sectionIdx].Settings.push_back(NewSetting);
settingIdx = Sections[sectionIdx].Settings.size()-1;
// Update the setting!
UpdateString:
Sections[sectionIdx].Settings[settingIdx].isNumber = false;
Sections[sectionIdx].Settings[settingIdx].String = String;
Sections[sectionIdx].Settings[settingIdx].value = 0;
}
// Obtains a numerical setting, if it exists, otherwise does nothing.
bool CINIFile::Get(string SectionName, string SettingName, int& value)
{
for (unsigned i = 0; i < Sections.size(); i++)
{
if ((Sections[i].Name == SectionName) ||
((Sections[i].Name == "") && (SectionName == DefaultSectionName)) || // accept alias for default section
((Sections[i].Name == DefaultSectionName) && (SectionName == ""))) // ...
{
for (unsigned j = 0; j < Sections[i].Settings.size(); j++)
{
if (Sections[i].Settings[j].Name == SettingName)
{
value = Sections[i].Settings[j].value;
return OKAY;
}
}
}
}
return FAIL;
}
bool CINIFile::Get(string SectionName, string SettingName, unsigned& value)
{
int intVal;
if (Get(SectionName, SettingName, intVal) == FAIL || intVal < 0)
return FAIL;
value = (unsigned)intVal;
return OKAY;
}
bool CINIFile::Get(string SectionName, string SettingName, bool& value)
{
int intVal;
if (Get(SectionName, SettingName, intVal) == FAIL)
return FAIL;
value = intVal > 0;
return OKAY;
}
// Obtains a string setting, if it exists, otherwise does nothing.
bool CINIFile::Get(string SectionName, string SettingName, string& String)
{
for (unsigned i = 0; i < Sections.size(); i++)
{
if ((Sections[i].Name == SectionName) ||
((Sections[i].Name == "") && (SectionName == DefaultSectionName)) || // accept alias for default section
((Sections[i].Name == DefaultSectionName) && (SectionName == ""))) // ...
{
for (unsigned j = 0; j < Sections[i].Settings.size(); j++)
{
if (Sections[i].Settings[j].Name == SettingName)
{
String = Sections[i].Settings[j].String;
return OKAY;
}
}
}
}
return FAIL;
}
void CINIFile::SetDefaultSectionName(string SectionName)
{
DefaultSectionName = SectionName;
}
/******************************************************************************
Tokenizer
Never need to check for newlines because it is assumed these have been
stripped by getline().
******************************************************************************/
// Token types
#define TOKEN_INVALID -1
#define TOKEN_NULL 0
#define TOKEN_IDENTIFIER 1
#define TOKEN_NUMBER 2
#define TOKEN_STRING 3
// Token constructor (initializes token to null)
CINIFile::CToken::CToken(void)
{
type = TOKEN_NULL;
}
// Returns true for white space, comment symbol, or null terminator.
static bool IsBlank(char c)
{
if (isspace(c) || (c==';') || (c=='\0'))
return true;
return false;
}
// Fetches a string. Tolerates all characters between quotes, except \n.
CINIFile::CToken CINIFile::GetString(void)
{
CToken T;
T.type = TOKEN_STRING;
// Search for next quote
++linePtr;
while (1)
{
if (linePtr[0] == '\"')
{
++linePtr; // so we can find next token
break;
}
else if ((linePtr[0] == '\0') || (linePtr[0] == '\n'))
{
//printf("tokenizer: warning: string is missing end quote\n");
break;
}
else
T.String += linePtr[0];
++linePtr;
}
return T;
}
//static bool IsOverflown(unsigned long long number, bool isNeg)
//{
// return (!isNeg && number > 0x000000007FFFFFFFULL) || (isNeg && number > 0x0000000080000000ULL);
//}
// Fetch number (decimal or hexadecimal positive/negative integer).
// linePtr must point to a character and therefore linePtr[1] is guaranteed to be within bounds.
CINIFile::CToken CINIFile::GetNumber(void)
{
CToken T;
unsigned long long number = 0;
bool isNeg = false;
//int overflow = 0;
T.type = TOKEN_NUMBER;
// See if begins with minus sign
if (linePtr[0]=='-')
{
isNeg = true;
linePtr++;
}
// Hexadecimal?
if ((linePtr[0]=='0') && ((linePtr[1]=='X') || (linePtr[1]=='x')))
{
linePtr += 2; // advance to digits
// Ensure that at we have at least one digit
if (!isxdigit(linePtr[0]))
{
//printf("tokenizer: invalid hexadecimal number\n");
T.type = TOKEN_INVALID;
return T;
}
// Read number digit by digit
while (1)
{
if (isxdigit(linePtr[0]))
{
number <<= 4;
if (isdigit(linePtr[0]))
number |= (linePtr[0]-'0');
else if (isupper(linePtr[0]))
number |= (linePtr[0]-'A');
else // must be lowercase...
number |= (linePtr[0]-'a');
++linePtr;
// Check for overflows
//if (IsOverflown(number, isNeg))
// overflow = 1;
}
else if (IsBlank(linePtr[0]))
break;
else
{
//printf("tokenizer: invalid hexadecimal number\n");
T.type = TOKEN_INVALID;
return T;
}
}
}
// Decimal?
else
{
// Read number digit by digit
while (1)
{
if (isdigit(linePtr[0]))
{
number *= 10;
number += (linePtr[0]-'0');
++linePtr;
// Check for overflows
//if (IsOverflown(number, isNeg))
// overflow = 1;
}
else if (IsBlank(linePtr[0]))
break;
else
{
//printf("tokenizer: invalid number\n");
T.type = TOKEN_INVALID;
return T;
}
}
}
//if (overflow)
// printf("tokenizer: number exceeds 32 bits and has been truncated\n");
T.number = (isNeg ? -(int)number : (int)number);
return T;
}
// Fetch identifier
CINIFile::CToken CINIFile::GetIdentifier(void)
{
CToken T;
T.type = TOKEN_IDENTIFIER;
while (1)
{
if (isalpha(linePtr[0]) || isdigit(linePtr[0]) || (linePtr[0]=='_'))
{
T.String += linePtr[0];
++linePtr;
}
else
break;
}
return T;
}
// Fetch token
CINIFile::CToken CINIFile::GetToken(void)
{
CToken T;
while (1)
{
// Gobble up whitespace
if (isspace(linePtr[0]))
++linePtr;
// Comment or end of line
else if ((linePtr[0]==';') || (linePtr[0]=='\0'))
{
T.type = TOKEN_NULL;
return T; // do not advance linePtr (so we do not de-sync the parser)
}
// Delimiters
else if ((linePtr[0]=='[') || (linePtr[0]==']') || (linePtr[0]=='='))
{
T.type = *linePtr++;
return T;
}
// Identifier?
else if (isalpha(linePtr[0]) || (linePtr[0] == '_'))
{
T = GetIdentifier();
return T;
}
// Number? (+/-?)
else if (linePtr[0]=='-' || isdigit(linePtr[0]))
{
T = GetNumber();
return T;
}
// String?
else if (linePtr[0]=='\"')
{
T = GetString();
return T;
}
// Illegal symbol
else
break; // return null token
}
// If we got here, invalid token
T.type = TOKEN_INVALID;
return T;
}
/******************************************************************************
Parser
******************************************************************************/
/*
* Parse tree is initialized with a blank section in case the user adds
* settings with defined sections before adding settings without an explicit
* section. If this is not done, settings without a section will be wrongly
* output as part of the previous section in the parse tree.
*/
void CINIFile::InitParseTree(void)
{
struct Section FirstSection;
FirstSection.Name = "";
Sections.clear();
Sections.push_back(FirstSection);
}
bool CINIFile::Parse(void)
{
CToken T, U, V, W;
string currentSection; // current section we're processing
bool parseStatus = OKAY;
lineNum = 0;
if (!File.is_open())
return FAIL;
File.clear();
if (!File.good())
return FAIL;
while (!File.eof())
{
++lineNum;
File.getline(lineBuf,2048);
if (File.fail())
return FAIL;
linePtr = lineBuf; // beginning of line
// Top level
T = GetToken();
U = GetToken();
V = GetToken();
W = GetToken(); // should always be null
switch (T.type)
{
// [ Identifier ]
case '[':
if ((U.type==TOKEN_IDENTIFIER) && (V.type==']') && (W.type==TOKEN_NULL))
{
//printf("Section: %s\n", U.String.c_str());
currentSection = U.String;
}
else
{
parseStatus = FAIL;
//printf("%d: parse error\n", lineNum);
}
break;
// Identifier '=' Argument
case TOKEN_IDENTIFIER:
if (U.type != '=')
{
parseStatus = FAIL;
//printf("%d: expected '=' after identifier\n", lineNum);
}
else
{
if (((V.type==TOKEN_NUMBER) || (V.type==TOKEN_STRING)) && (W.type==TOKEN_NULL))
{
if (V.type == TOKEN_NUMBER)
{
//printf("\t%s = %X\n", T.String.c_str(), V.number);
Set(currentSection, T.String, V.number);
}
else if (V.type == TOKEN_STRING)
{
//printf("\t%s = %s\n", T.String.c_str(), V.String.c_str());
Set(currentSection, T.String, V.String);
}
}
else
{
parseStatus = FAIL;
//printf("%d: expected a number or string after '='\n", lineNum);
}
}
break;
// Blank line
case TOKEN_NULL:
break;
// Illegal
default:
parseStatus = FAIL;
//printf("%d: parse error\n", lineNum);
break;
}
}
//printf("end of file reached\n");
return parseStatus;
}

View file

@ -1,245 +0,0 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski, Nik Henson
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* INIFile.h
*
* Header file for INI file management.
*/
#ifndef INCLUDED_INIFILE_H
#define INCLUDED_INIFILE_H
// Standard C++ and STL headers
#include <fstream>
#include <string>
#include <vector>
using namespace std;
#include "Types.h"
/*
* CINIFile:
*
* INI file parser.
*/
class CINIFile
{
public:
/*
* Get(SectionName, SettingName, value):
* Get(SectionName, SettingName, String):
*
* Obtains the value of a setting associated with a particular section. It
* is assumed that the caller knows whether the setting should be a string
* or an integer value. If the setting was specified as a string in the
* INI file, the value will be set to 0. Otherwise, the string will be set
* to "".
*
* Parameters:
* SectionName String defining the section name.
* SettingName String defining the setting name.
* value Reference to where the setting value will be
* copied.
* String Reference to where the string will be copied.
*
* Returns:
* OKAY if the setting was found, FAIL otherwise. The type is not
* checked. If the setting is not found, the output parameter will not
* be modified.
*/
bool Get(string SectionName, string SettingName, int& value);
bool Get(string SectionName, string SettingName, unsigned& value);
bool Get(string SectionName, string SettingName, bool& value);
bool Get(string SectionName, string SettingName, string& String);
/*
* Set(SectionName, SettingName, value):
* Set(SectionName, SettingName, String):
*
* Sets a setting associated with a particular section. For each overload
* type (string or integer), the opposite type is cleard (0 is written to
* values when a string is set, "" is written to strings when a value is
* set). If the setting does not exist, it is created. If the section does
* not exist, it will be added as well.
*
* Parameters:
* SectionName String defining the section name.
* SettingName String defining the setting name.
* value Value to write. String will be set to "".
* String String to write. Value will be set to 0.
*/
void Set(string SectionName, string SettingName, int value);
void Set(string SectionName, string SettingName, string String);
/*
* Write(comment):
*
* Outputs the parse tree to the INI file. The current contents of the file
* on the disk are discarded and overwritten. This means that comments are
* lost. The file is also put into write mode and cannot be re-parsed.
*
* Parameters:
* comment An optional C-string containing a comment to insert at
* the beginning of the file, otherwise NULL. The comment
* lines must include semicolons at the beginning, they
* will not be inserted automatically. The string is
* output directly, as-is.
*
* Returns:
* OKAY if successful. FAIL if an error occurred at any point. In
* order to truncate the original contents of the file, this function
* closes the file, reopends it as write-only, then reopens it again
* as a read/write file. If an error occurs during the reopening
* procedure, it is possible that nothing will be output and the
* previous contents will be lost.
*/
bool Write(const char *comment);
/*
* Parse(void):
*
* Parses the contents of the file, building the parse tree. Settings
* already present in the parse tree will continue to exist and will be
* overwritten if new, matching settings are found in the file.
*
* This should be done once and at the beginning.
*
* Returns:
* OKAY if successful, FAIL if there was a file or parse error.
*/
bool Parse(void);
/*
* SetDefaultSectionName(SectionName):
*
* Sets the default section name. Any settings not associated with a
* particular section (ie. those assigned to a blank section, "") will be
* output under this section when Write() is called.
*
* This should be called before parsing and before adding any settings.
* If the same setting is added to the default section, "", and a section
* named "Global", and afterwards "Global" is set as the default name,
* the setting originally in the default section will be the one that is
* subsequently accessible (the Get()/Set() methods look for the first
* match). However, when the file is written out, the second setting
* will be written out as well using the same section name and, thus,
* when the INI file is re-parsed, its value will be used instead.
*
* Parameters:
* SectionName String defining the section name.
*/
void SetDefaultSectionName(string SectionName);
/*
* Open(fileNameStr):
*
* Opens an INI file. The file must already exist. A new one will not be
* created. Do not open another file before closing the current one!
*
* Parameters:
* fileNameStr File path (C string).
*
* Returns:
* OKAY if successful, FAIL if unable to open for reading and writing.
*/
bool Open(const char *fileNameStr);
/*
* OpenAndCreate(fileNameStr):
*
* Opens an INI file and, if it does not exist, creates a new one. Do not
* open another file before closing the current one!
*
* Parameters:
* fileNameStr File path (C string).
*
* Returns:
* OKAY if successful, FAIL if unable to open file.
*/
bool OpenAndCreate(const char *fileNameStr);
/*
* Close(void):
*
* Closes the INI file and clears the parse tree.
*/
void Close(void);
private:
// Token
class CToken
{
public:
int type; // token type (defined privately in INIFile.cpp)
int number; // numbers and bools
string String; // strings and identifiers
// Constructor (initialize to null token)
CToken(void);
};
// Parse tree
bool LookUpSection(unsigned *idx, string SectionName);
void InitParseTree(void);
// Tokenizer
CToken GetString(void);
CToken GetNumber(void);
CToken GetIdentifier(void);
CToken GetToken(void);
// File state
fstream File;
string FileName; // name of last file opened
// Default section name (name to use for the blank section)
string DefaultSectionName;
// Parser state
char lineBuf[2048]; // holds current line
char *linePtr; // points to current position within line (for tokenization)
unsigned lineNum; // line number
// Parse tree: a list of sections each of which is a list of settings for that section
struct Setting // it is up to caller to determine whether to use value or string
{
string Name; // setting name
bool isNumber; // internal flag: true if the setting is a number, false if it is a string
int value; // value of number
string String; // string
Setting(void)
{
value = 0; // initialize value to 0
isNumber = true; // indicate the setting is initially a number
}
};
struct Section
{
string Name; // section name
vector<struct Setting> Settings; // list of settings associated w/ this section
};
vector<struct Section> Sections; // a list of sections
};
#endif // INCLUDED_INIFILE_H

View file

@ -179,36 +179,6 @@ void CInput::StoreToConfig(Util::Config::Node *config)
config->Set(key, m_mapping);
}
void CInput::ReadFromINIFile(CINIFile *ini, const char *section)
{
// See if input is configurable
if (IsConfigurable())
{
// If so, check INI file for mapping string
string key("Input");
key.append(id);
string mapping;
if (ini->Get(section, key, mapping) == OKAY)
{
// If found, then set mapping string
SetMapping(mapping.c_str());
return;
}
}
// If input has not been configured, then force recreation of source anyway since input system settings may have changed
CreateSource();
}
void CInput::WriteToINIFile(CINIFile *ini, const char *section)
{
if (!IsConfigurable())
return;
string key("Input");
key.append(id);
ini->Set(section, key, m_mapping);
}
void CInput::InputSystemChanged()
{
// If input system or its settings have changed, then force recreation of source

View file

@ -35,7 +35,6 @@
class CInputSource;
class CInputSystem;
class CINIFile;
// Flags for inputs
#define INPUT_FLAGS_SWITCH 0x0001
@ -154,13 +153,11 @@ public:
* Loads the input's mapping(s) from the given config object, as well as any other settings.
*/
virtual void LoadFromConfig(const Util::Config::Node &config);
virtual void ReadFromINIFile(CINIFile *ini, const char *section);
/*
* Stores the current input mapping(s) to the given config object, as well as any other settings.
*/
virtual void StoreToConfig(Util::Config::Node *config);
virtual void WriteToINIFile(CINIFile *ini, const char *section);
void InputSystemChanged();

View file

@ -1115,39 +1115,6 @@ void CInputSystem::StoreKeySettings(Util::Config::Node *config, KeySettings *set
config->Set(baseKey + "DecaySpeed", settings->decaySpeed);
}
KeySettings *CInputSystem::ReadKeySettings(CINIFile *ini, const char *section, int kbdNum)
{
// Get common key settings and create new key settings based on that
KeySettings *common = (kbdNum != ANY_KEYBOARD ? GetKeySettings(ANY_KEYBOARD, true) : &m_defKeySettings);
KeySettings *settings = new KeySettings(*common);
settings->kbdNum = kbdNum;
// Read settings from ini file
string baseKey("InputKey");
if (kbdNum != ANY_KEYBOARD)
baseKey.append(IntToString(kbdNum + 1));
bool read = false;
read |= ini->Get(section, baseKey + "Sensitivity", settings->sensitivity) == OKAY;
read |= ini->Get(section, baseKey + "DecaySpeed", settings->decaySpeed) == OKAY;
if (read)
return settings;
delete settings;
return NULL;
}
void CInputSystem::WriteKeySettings(CINIFile *ini, const char *section, KeySettings *settings)
{
// Get common key settings
KeySettings *common = (settings->kbdNum != ANY_KEYBOARD ? GetKeySettings(ANY_KEYBOARD, true) : &m_defKeySettings);
// Write to ini file any settings that are different to common settings
string baseKey("InputKey");
if (settings->kbdNum != ANY_KEYBOARD)
baseKey.append(IntToString(settings->kbdNum + 1));
if (settings->sensitivity != common->sensitivity) ini->Set(section, baseKey + "Sensitivity", settings->sensitivity);
if (settings->decaySpeed != common->decaySpeed) ini->Set(section, baseKey + "DecaySpeed", settings->decaySpeed);
}
void CInputSystem::PrintMouseSettings(int mseNum, MouseSettings *settings)
{
for (int axisNum = 0; axisNum < NUM_MOUSE_AXES; axisNum++)
@ -1198,42 +1165,6 @@ void CInputSystem::StoreMouseSettings(Util::Config::Node *config, MouseSettings
}
}
MouseSettings *CInputSystem::ReadMouseSettings(CINIFile *ini, const char *section, int mseNum)
{
// Get common mouse settings and create new mouse settings based on that
MouseSettings *common = (mseNum != ANY_MOUSE ? GetMouseSettings(ANY_MOUSE, true) : &m_defMseSettings);
MouseSettings *settings = new MouseSettings(*common);
settings->mseNum = mseNum;
// Read settings from ini file
string baseKey("InputMouse");
if (mseNum != ANY_MOUSE)
baseKey.append(IntToString(mseNum + 1));
bool read = false;
for (int axisNum = 0; axisNum < NUM_MOUSE_AXES; axisNum++)
read |= ini->Get(section, baseKey + s_axisIds[axisNum] + "DeadZone", settings->deadZones[axisNum]) == OKAY;
if (read)
return settings;
delete settings;
return NULL;
}
void CInputSystem::WriteMouseSettings(CINIFile *ini, const char *section, MouseSettings *settings)
{
// Get common mouse settings
MouseSettings *common = (settings->mseNum != ANY_MOUSE ? GetMouseSettings(ANY_MOUSE, true) : &m_defMseSettings);
// Write to ini file any settings that are different to common/default settings
string baseKey("InputMouse");
if (settings->mseNum != ANY_MOUSE)
baseKey.append(IntToString(settings->mseNum + 1));
for (int axisNum = 0; axisNum < NUM_MOUSE_AXES; axisNum++)
{
if (settings->deadZones[axisNum] != common->deadZones[axisNum])
ini->Set(section, baseKey + s_axisIds[axisNum] + "DeadZone", settings->deadZones[axisNum]);
}
}
void CInputSystem::PrintJoySettings(int joyNum, JoySettings *settings)
{
const JoyDetails *joyDetails = (joyNum != ANY_JOYSTICK ? GetJoyDetails(joyNum) : NULL);
@ -1327,58 +1258,6 @@ void CInputSystem::StoreJoySettings(Util::Config::Node *config, JoySettings *set
}
}
JoySettings *CInputSystem::ReadJoySettings(CINIFile *ini, const char *section, int joyNum)
{
// Get common/default joystick settings and create new joystick settings based on that
JoySettings *common = (joyNum != ANY_JOYSTICK ? GetJoySettings(ANY_JOYSTICK, true) : &m_defJoySettings);
JoySettings *settings = new JoySettings(*common);
settings->joyNum = joyNum;
// Read settings from ini file
string baseKey("InputJoy");
if (joyNum != ANY_JOYSTICK)
baseKey.append(IntToString(joyNum + 1));
bool read = false;
for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++)
{
const char *axisId = s_axisIds[axisNum];
read |= ini->Get(section, baseKey + axisId + "MinVal", settings->axisMinVals[axisNum]) == OKAY;
read |= ini->Get(section, baseKey + axisId + "OffVal", settings->axisOffVals[axisNum]) == OKAY;
read |= ini->Get(section, baseKey + axisId + "MaxVal", settings->axisMaxVals[axisNum]) == OKAY;
read |= ini->Get(section, baseKey + axisId + "DeadZone", settings->deadZones[axisNum]) == OKAY;
read |= ini->Get(section, baseKey + axisId + "Saturation", settings->saturations[axisNum]) == OKAY;
}
if (read)
return settings;
delete settings;
return NULL;
}
void CInputSystem::WriteJoySettings(CINIFile *ini, const char *section, JoySettings *settings)
{
// Get common/default joystick settings
JoySettings *common = (settings->joyNum != ANY_JOYSTICK ? GetJoySettings(ANY_JOYSTICK, true) : &m_defJoySettings);
// Write to ini file any settings that are different to common/default settings
string baseKey("InputJoy");
if (settings->joyNum != ANY_JOYSTICK)
baseKey.append(IntToString(settings->joyNum + 1));
for (int axisNum = 0; axisNum < NUM_JOY_AXES; axisNum++)
{
const char *axisId = s_axisIds[axisNum];
if (settings->axisMinVals[axisNum] != common->axisMinVals[axisNum])
ini->Set(section, baseKey + axisId + "MinVal", settings->axisMinVals[axisNum]);
if (settings->axisOffVals[axisNum] != common->axisOffVals[axisNum])
ini->Set(section, baseKey + axisId + "OffVal", settings->axisOffVals[axisNum]);
if (settings->axisMaxVals[axisNum] != common->axisMaxVals[axisNum])
ini->Set(section, baseKey + axisId + "MaxVal", settings->axisMaxVals[axisNum]);
if (settings->deadZones[axisNum] != common->deadZones[axisNum])
ini->Set(section, baseKey + axisId + "DeadZone", settings->deadZones[axisNum]);
if (settings->saturations[axisNum] != common->saturations[axisNum])
ini->Set(section, baseKey + axisId + "Saturation", settings->saturations[axisNum]);
}
}
KeySettings *CInputSystem::GetKeySettings(int kbdNum, bool useDefault)
{
KeySettings *common = NULL;
@ -1844,60 +1723,6 @@ void CInputSystem::StoreToConfig(Util::Config::Node *config)
StoreJoySettings(config, *it);
}
void CInputSystem::ReadFromINIFile(CINIFile *ini, const char *section)
{
ClearSettings();
ClearSourceCache();
// Read all key settings for attached keyboards
KeySettings *keySettings = ReadKeySettings(ini, section, ANY_KEYBOARD);
if (keySettings != NULL)
m_keySettings.push_back(keySettings);
for (int kbdNum = 0; kbdNum < m_numKbds; kbdNum++)
{
keySettings = ReadKeySettings(ini, section, kbdNum);
if (keySettings != NULL)
m_keySettings.push_back(keySettings);
}
// Read all mouse settings for attached mice
MouseSettings *mseSettings = ReadMouseSettings(ini, section, ANY_MOUSE);
if (mseSettings != NULL)
m_mseSettings.push_back(mseSettings);
for (int mseNum = 0; mseNum < m_numMice; mseNum++)
{
mseSettings = ReadMouseSettings(ini, section, mseNum);
if (mseSettings != NULL)
m_mseSettings.push_back(mseSettings);
}
// Read all joystick settings for attached joysticks
JoySettings *joySettings = ReadJoySettings(ini, section, ANY_JOYSTICK);
if (joySettings != NULL)
m_joySettings.push_back(joySettings);
for (int joyNum = 0; joyNum < m_numJoys; joyNum++)
{
joySettings = ReadJoySettings(ini, section, joyNum);
if (joySettings != NULL)
m_joySettings.push_back(joySettings);
}
}
void CInputSystem::WriteToINIFile(CINIFile *ini, const char *section)
{
// Write all key settings
for (vector<KeySettings*>::iterator it = m_keySettings.begin(); it != m_keySettings.end(); it++)
WriteKeySettings(ini, section, *it);
// Write all mouse settings
for (vector<MouseSettings*>::iterator it = m_mseSettings.begin(); it != m_mseSettings.end(); it++)
WriteMouseSettings(ini, section, *it);
// Write all joystick settings
for (vector<JoySettings*>::iterator it = m_joySettings.begin(); it != m_joySettings.end(); it++)
WriteJoySettings(ini, section, *it);
}
bool CInputSystem::ReadMapping(char *buffer, unsigned bufSize, bool fullAxisOnly, unsigned readFlags, const char *escapeMapping)
{
// Map given escape mapping to an input source

View file

@ -39,7 +39,6 @@ using namespace std;
class CInput;
class CInputSource;
class CINIFile;
#define MAX_NAME_LENGTH 255
@ -480,13 +479,11 @@ private:
* Returns NULL if no relevant settings were found in the INI file.
*/
KeySettings *LoadKeySettings(const Util::Config::Node &config, int kbdNum);
KeySettings *ReadKeySettings(CINIFile *ini, const char *section, int kbdNum);
/*
* Writes the given key settings to an INI file, only writing out settings that are different to their defaults.
*/
void StoreKeySettings(Util::Config::Node *config, KeySettings *settings);
void WriteKeySettings(CINIFile *ini, const char *section, KeySettings *settings);
/*
* Prints the given mouse settings to stdout.
@ -498,13 +495,11 @@ private:
* Returns NULL if no relevant settings were found in the config object.
*/
MouseSettings *LoadMouseSettings(const Util::Config::Node &config, int mseNum);
MouseSettings *ReadMouseSettings(CINIFile *ini, const char *section, int mseNum);
/*
* Stores the given mouse settings to a config object, only storing settings that differ from their defaults.
*/
void StoreMouseSettings(Util::Config::Node *config, MouseSettings *settings);
void WriteMouseSettings(CINIFile *ini, const char *section, MouseSettings *settings);
/*
* Prints the given joystick settings to stdout.
@ -516,13 +511,11 @@ private:
* Returns NULL if no relevant settings were found in the config object.
*/
JoySettings *LoadJoySettings(const Util::Config::Node &config, int joyNum);
JoySettings *ReadJoySettings(CINIFile *ini, const char *section, int joyNum);
/*
* Stores the given joystick settings to a config object, only storing settings that differ from their defaults.
*/
void StoreJoySettings(Util::Config::Node *config, JoySettings *settings);
void WriteJoySettings(CINIFile *ini, const char *section, JoySettings *settings);
protected:
// Current display geometry
@ -806,13 +799,11 @@ public:
* Reads all keyboard, mouse and joystick settings (and any additional system-specific additional settings) from the given config object.
*/
virtual void LoadFromConfig(const Util::Config::Node &config);
virtual void ReadFromINIFile(CINIFile *ini, const char *section);
/*
* Stores all keyboard, mouse and joystick settings (and any additional system-specific settings) to the given config object.
*/
virtual void StoreToConfig(Util::Config::Node *config);
virtual void WriteToINIFile(CINIFile *ini, const char *section);
/*
* Returns the current key settings for given keyboard number, or common settings if ANY_KEYBOARD specified.

View file

@ -182,24 +182,21 @@ CTriggerInput::CTriggerInput(const char *inputId, const char *inputLabel, unsign
//
}
void CTriggerInput::ReadFromINIFile(CINIFile *ini, const char *section)
void CTriggerInput::LoadFromConfig(const Util::Config::Node &config)
{
CInput::ReadFromINIFile(ini, section);
string key("Input");
key.append(id);
unsigned autoTrigger;
if (ini->Get(section, key, autoTrigger) == OKAY)
m_autoTrigger = !!autoTrigger;
auto *node = config.TryGet(key);
if (node)
m_autoTrigger = !!node->ValueAs<unsigned>();
}
void CTriggerInput::WriteToINIFile(CINIFile *ini, const char *section)
void CTriggerInput::StoreToConfig(Util::Config::Node *config)
{
CInput::WriteToINIFile(ini, section);
string key("Input");
key.append(id);
ini->Set(section, key, (unsigned)m_autoTrigger);
config->Set(key, (unsigned) m_autoTrigger);
}
void CTriggerInput::Poll()

View file

@ -159,9 +159,9 @@ public:
CTriggerInput(const char *inputId, const char *inputLabel, unsigned inputGameFlags, CSwitchInput *triggerInput, CSwitchInput *offscreenInput,
UINT16 offVal = 0x00, UINT16 onVal = 0x01);
void ReadFromINIFile(CINIFile *ini, const char *section);
void LoadFromConfig(const Util::Config::Node &config);
void WriteToINIFile(CINIFile *ini, const char *section);
void StoreToConfig(Util::Config::Node *config);
/*
* Polls (updates) the input, updating its trigger value and offscreen value from the switch inputs

View file

@ -421,22 +421,6 @@ void CInputs::StoreToConfig(Util::Config::Node *config)
(*it)->StoreToConfig(config);
}
void CInputs::ReadFromINIFile(CINIFile *ini, const char *section)
{
m_system->ReadFromINIFile(ini, section);
for (vector<CInput*>::iterator it = m_inputs.begin(); it != m_inputs.end(); it++)
(*it)->ReadFromINIFile(ini, section);
}
void CInputs::WriteToINIFile(CINIFile *ini, const char *section)
{
m_system->WriteToINIFile(ini, section);
for (vector<CInput*>::iterator it = m_inputs.begin(); it != m_inputs.end(); it++)
(*it)->WriteToINIFile(ini, section);
}
bool CInputs::ConfigureInputs(const Game *game)
{
m_system->UngrabMouse();

View file

@ -41,7 +41,6 @@ class CAxisInput;
class CSwitchInput;
class CGearShift4Input;
class CTriggerInput;
class CINIFile;
struct Game;
/*
@ -270,13 +269,11 @@ public:
* Loads the input mapping assignments from the given config object.
*/
void LoadFromConfig(const Util::Config::Node &config);
void ReadFromINIFile(CINIFile *ini, const char *section);
/*
* Stores the current input mapping assignments to the given config object.
*/
void StoreToConfig(Util::Config::Node *config);
void WriteToINIFile(CINIFile *ini, const char *section);
/*
* Configures the current input mapping assignments for the given game, or all inputs if game is NULL, by asking the user for input.

View file

@ -1,509 +0,0 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski, Nik Henson
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* ROMLoad.cpp
*
* ROM loading functions.
*/
#include <new>
#include <cstring>
#include "Supermodel.h"
#include "Pkgs/unzip.h"
static bool IsPowerOfTwo(long x)
{
while (((x & 1) == 0) && x > 1) // while x is even and > 1
x >>= 1;
return (x == 1);
}
static struct GameInfo cromInfo =
{
"crom.bin",
NULL,
"Custom CROM Image",
"Bart Trzynadlowski",
2015,
0x10,
0, // size of CROM image (filled in at run time)
false, // no need to mirror anything
0, // no VROM
0, // no sample ROMs
GAME_INPUT_COMMON|GAME_INPUT_JOYSTICK1,
0, // no MPEG board
false, // no drive board
0, // no security board
{
{ NULL, false, NULL, 0, 0, 0, 0, 0, false }
}
};
static GameInfo * LoadCROMDirect(const struct ROMMap *Map, const char *file)
{
FILE *fp = fopen(file, "rb");
if (!fp)
{
ErrorLog("Could not open '%s'.", file);
return NULL;
}
fseek(fp, 0, SEEK_END);
long fileSize = ftell(fp);
rewind(fp);
if (fileSize > 0x800000)
{
ErrorLog("CROM image exceeds 8MB.");
fclose(fp);
return NULL;
}
if (!IsPowerOfTwo(fileSize))
{
ErrorLog("CROM image size is not a power of 2.");
fclose(fp);
return NULL;
}
while (Map->region && strcmp(Map->region, "CROM"))
++Map;
if (!Map->region)
{
ErrorLog("Internal error: No CROM region in ROM map!");
fclose(fp);
return NULL;
}
// Read file into upper part of CROM region
fread(Map->ptr + 0x800000 - fileSize, sizeof(UINT8), fileSize, fp);
fclose(fp);
// Return fake game info structure
cromInfo.cromSize = fileSize;
return &cromInfo;
}
/*
* CopyRegion(dest, destOffset, destSize, src, srcSize):
*
* Repeatedly mirror (copy) to destination from source until destination is
* filled.
*
* Parameters:
* dest Destination region.
* destOffset Offset within destination to begin mirroring to.
* destSize Size in bytes of destination region.
* src Source region to copy from.
* srcSize Size of region to copy from.
*/
void CopyRegion(UINT8 *dest, unsigned destOffset, unsigned destSize, UINT8 *src, unsigned srcSize)
{
if (!destSize || !srcSize)
return;
while (destOffset < destSize)
{
// If we'll overrun the destination, trim the copy length
if ((destOffset+srcSize) >= destSize)
srcSize = destSize-destOffset;
// Copy!
memcpy(&dest[destOffset], src, srcSize);
destOffset += srcSize;
}
}
// Search for a ROM within a single game based on its CRC
static bool FindROMByCRCInGame(const struct GameInfo **gamePtr, int *romIdxPtr, const struct GameInfo *Game, UINT32 crc)
{
for (int j = 0; Game->ROM[j].region != NULL; j++)
{
if (crc == Game->ROM[j].crc) // found it!
{
*gamePtr = Game; // I know this seems redundant, but we do it here because FindROMByCRC() uses this function
*romIdxPtr = j;
return OKAY;
}
}
return FAIL;
}
// Search for a ROM in the complete game list based on CRC32 and return its GameInfo and ROMInfo entries
static bool FindROMByCRC(const struct GameInfo **gamePtr, int *romIdxPtr, const struct GameInfo *GameList, const struct GameInfo *TryGame, UINT32 crc)
{
if (TryGame != NULL)
{
if (FindROMByCRCInGame(gamePtr, romIdxPtr, TryGame, crc) == OKAY)
return OKAY;
}
for (int i = 0; GameList[i].title != NULL; i++)
{
if (FindROMByCRCInGame(gamePtr, romIdxPtr, &(GameList[i]), crc) == OKAY)
return OKAY;
}
return FAIL;
}
// Returns true if this ROM appears only a single time in the entire game list (ie., it is not shared between games)
static bool ROMIsUnique(const struct GameInfo *GameList, UINT32 crc)
{
int timesFound = 0;
for (int i = 0; GameList[i].title != NULL; i++)
{
for (int j = 0; GameList[i].ROM[j].region != NULL; j++)
{
if (crc == GameList[i].ROM[j].crc)
timesFound++;
}
}
return (timesFound == 1) ? true : false;
}
static void ByteSwap(UINT8 *buf, unsigned size)
{
for (size_t i = 0; i < size; i += 2)
{
UINT8 x = buf[i+0];
buf[i+0] = buf[i+1];
buf[i+1] = x;
}
}
// Load a single ROM file
static bool LoadROM(UINT8 *buf, unsigned bufSize, const struct ROMMap *Map, const struct ROMInfo *ROM, unzFile zf, const char *zipFile, bool loadAll)
{
char file[2048+1];
unz_file_info fileInfo;
// Read the file into the buffer
int err = unzGetCurrentFileInfo(zf, &fileInfo, file, 2048, NULL, 0, NULL, 0);
if (err != UNZ_OK)
return ErrorLog("Unable to extract a file name from '%s'.", zipFile);
if (fileInfo.uncompressed_size != ROM->fileSize)
return ErrorLog("'%s' in '%s' is not the correct size (must be %d bytes).", file, zipFile, ROM->fileSize);
err = unzOpenCurrentFile(zf);
if (UNZ_OK != err)
return ErrorLog("Unable to read '%s' from '%s'.", file, zipFile);
size_t bytes = unzReadCurrentFile(zf, buf, bufSize);
if (bytes != ROM->fileSize)
{
unzCloseCurrentFile(zf);
return ErrorLog("Unable to read '%s' from '%s'.", file, zipFile);
}
err = unzCloseCurrentFile(zf);
if (UNZ_CRCERROR == err)
ErrorLog("CRC error reading '%s' from '%s'. File may be corrupt.", file, zipFile);
// Byte swap
if (ROM->byteSwap)
ByteSwap(buf, ROM->fileSize);
// Find out how to map the ROM and do it
for (size_t i = 0; Map[i].region != NULL; i++)
{
if (!strcmp(Map[i].region, ROM->region))
{
size_t destIdx = ROM->offset;
for (size_t srcIdx = 0; srcIdx < ROM->fileSize; )
{
for (size_t j = 0; j < ROM->groupSize; j++)
Map[i].ptr[destIdx+j] = buf[srcIdx++];
destIdx += ROM->stride;
}
return OKAY;
}
}
if (loadAll) // need to load all ROMs, so there should be no unmapped regions
return ErrorLog("%s:%d: No mapping for '%s'.", __FILE__, __LINE__, ROM->region);
else
return OKAY;
}
/*
* LoadROMSetFromZIPFile(Map, GameList, zipFile):
*
* Loads a complete ROM set from a ZIP archive. Automatically detects the game.
* If multiple games exist within the archive, an error will be printed and all
* but the first detected game will be ignored.
*
* Parameters:
* Map A list of pointers to the memory buffers for each ROM
* region.
* GameList List of all supported games and their ROMs.
* zipFile ZIP file to load from.
* loadAll If true, will check to ensure all ROMs were loaded.
* Otherwise, omits this check and loads only specified
* regions.
*
* Returns:
* Pointer to GameInfo struct for loaded game if successful, NULL
* otherwise. Prints errors.
*/
const struct GameInfo * LoadROMSetFromZIPFile(const struct ROMMap *Map, const struct GameInfo *GameList, const char *zipFile, bool loadAll)
{
if (!strcmp(zipFile, "crom.bin"))
return LoadCROMDirect(Map, zipFile);
const struct GameInfo *Game = NULL;
const struct GameInfo *CurGame; // this is the game to which the last ROM found is thought to belong
unz_file_info fileInfo;
string zipFileParent, zfpErr = "";
int romIdx = 0; // index within Game->ROM
unsigned romsFound[sizeof(Game->ROM)/sizeof(struct ROMInfo)];
bool multipleGameError = false;
// Try to open file
unzFile zf = unzOpen(zipFile);
if (NULL == zf)
{
ErrorLog("Could not open '%s'.", zipFile);
return NULL;
}
// First pass: scan every file and determine the game
int err = unzGoToFirstFile(zf);
if (UNZ_OK != err)
{
ErrorLog("Unable to read the contents of '%s' (code %X)", zipFile, err);
return NULL;
}
for (; err != UNZ_END_OF_LIST_OF_FILE; err = unzGoToNextFile(zf))
{
// Identify the file we're looking at
err = unzGetCurrentFileInfo(zf, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
if (err != UNZ_OK)
continue;
if (OKAY != FindROMByCRC(&CurGame, &romIdx, GameList, Game, fileInfo.crc))
continue;
// If the ROM appears in multiple games, do not use it to identify the game!
if (!ROMIsUnique(GameList, fileInfo.crc))
continue;
// We have a unique ROM used by a single game; identify that game
if (Game == NULL) // this is the first game we've identified within the ZIP
{
Game = CurGame;
DebugLog("ROM set identified: %s (%s), %s\n", Game->id, Game->title, zipFile);
}
else // we've already identified a game
{
if (CurGame != Game) // another game?
{
DebugLog("%s also contains: %s (%s)\n", zipFile, CurGame->id, CurGame->title);
if (multipleGameError == false) // only warn about this once
{
ErrorLog("Multiple games were found in '%s'; loading '%s'.", zipFile, Game->title);
multipleGameError = true;
}
}
}
}
if (Game == NULL)
{
ErrorLog("No Model 3 games found in '%s'.", zipFile);
unzClose(zf);
return NULL;
}
unzFile zfp = 0;
if (CurGame->parent)
{
// Create parent zip file name
string path = "";
if (strstr(zipFile, "/"))
{
path = string(zipFile);
path = path.substr(0, path.find_last_of("/") + 1);
}
if (strstr(zipFile, "\\"))
{
path = string(zipFile);
path = path.substr(0, path.find_last_of("\\") + 1);
}
zipFileParent = path + CurGame->parent + ".zip";
// Create error message
zfpErr = " or '" + string(zipFileParent) + "'";
// Try to open file
zfp = unzOpen(zipFileParent.c_str());
if (NULL == zfp)
{
ErrorLog("Parent ROM set '%s' is missing.", zipFileParent.c_str());
unzClose(zf);
return NULL;
}
}
// Second pass: check if all ROM files for the identified game are present
err = unzGoToFirstFile(zf);
if (UNZ_OK != err)
{
ErrorLog("Unable to read the contents of '%s' (code %X)", zipFile, err);
unzClose(zf);
return NULL;
}
memset(romsFound, 0, sizeof(romsFound)); // here, romsFound[] indicates which ROMs were found in the ZIP file for the game
for (; err != UNZ_END_OF_LIST_OF_FILE; err = unzGoToNextFile(zf))
{
// Identify the file we're looking at
err = unzGetCurrentFileInfo(zf, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
if (err != UNZ_OK)
continue;
// If it's not part of the game we've identified, skip it
if (OKAY != FindROMByCRCInGame(&CurGame, &romIdx, Game, fileInfo.crc))
continue;
// If we have found a ROM for the correct game, mark its corresponding indicator
romsFound[romIdx] = 1;
}
if (zfp)
{
err = unzGoToFirstFile(zfp);
if (UNZ_OK != err)
{
ErrorLog("Unable to read the contents of '%s' (code %X)", zipFileParent.c_str(), err);
unzClose(zf);
return NULL;
}
for (; err != UNZ_END_OF_LIST_OF_FILE; err = unzGoToNextFile(zfp))
{
// Identify the file we're looking at
err = unzGetCurrentFileInfo(zfp, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
if (err != UNZ_OK)
continue;
// If it's not part of the game we've identified, skip it
if (OKAY != FindROMByCRCInGame(&CurGame, &romIdx, Game, fileInfo.crc))
continue;
// If we have found a ROM for the correct game, mark its corresponding indicator
romsFound[romIdx] = 1;
}
}
// Compute how many ROM files this game has
size_t numROMs = 0;
for (; Game->ROM[numROMs].region != NULL; numROMs++)
;
// If not all ROMs were present, tell the user
err = OKAY;
for (size_t i = 0; i < numROMs; i++)
{
if ((0 == romsFound[i]) && !Game->ROM[i].optional) // if not found and also not optional
err |= (int) ErrorLog("'%s' (CRC=%08X) is missing from '%s'%s.", Game->ROM[i].fileName, Game->ROM[i].crc, zipFile, zfp ? zfpErr.c_str() : "");
}
if (err != OKAY)
{
unzClose(zf);
if (zfp) unzClose(zfp);
return NULL;
}
// Allocate a scratch buffer big enough to hold the biggest ROM
size_t maxSize = 0;
for (size_t i = 0; i < numROMs; i++)
{
if (Game->ROM[i].fileSize > maxSize)
maxSize = Game->ROM[i].fileSize;
}
UINT8 *buf = new(std::nothrow) UINT8[maxSize];
if (NULL == buf)
{
unzClose(zf);
if (zfp) unzClose(zfp);
ErrorLog("Insufficient memory to load ROM files (%d bytes).", maxSize);
return NULL;
}
// Third pass: load the ROMs
memset(romsFound, 0, sizeof(romsFound)); // now, romsFound[] is used to indicate whether we successfully loaded the ROM
err = unzGoToFirstFile(zf);
if (UNZ_OK != err)
{
ErrorLog("Unable to read the contents of '%s' (code %X).", zipFile, err);
err = FAIL;
goto Quit;
}
for (; err != UNZ_END_OF_LIST_OF_FILE; err = unzGoToNextFile(zf))
{
err = unzGetCurrentFileInfo(zf, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
if (err != UNZ_OK)
continue;
// If this ROM is not part of the game we're loading, skip it
if (OKAY != FindROMByCRCInGame(&CurGame, &romIdx, Game, fileInfo.crc))
continue;
// Load the ROM and mark that we did so successfully
if (OKAY == LoadROM(buf, maxSize, Map, &Game->ROM[romIdx], zf, zipFile, loadAll))
romsFound[romIdx] = 1; // success! mark as loaded
}
if (zfp)
{
err = unzGoToFirstFile(zfp);
if (UNZ_OK != err)
{
ErrorLog("Unable to read the contents of '%s' (code %X).", zipFileParent.c_str(), err);
err = FAIL;
goto Quit;
}
for (; err != UNZ_END_OF_LIST_OF_FILE; err = unzGoToNextFile(zfp))
{
err = unzGetCurrentFileInfo(zfp, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
if (err != UNZ_OK)
continue;
// If this ROM is not part of the game we're loading, skip it
if (OKAY != FindROMByCRCInGame(&CurGame, &romIdx, Game, fileInfo.crc))
continue;
// Load the ROM and mark that we did so successfully
if (OKAY == LoadROM(buf, maxSize, Map, &Game->ROM[romIdx], zfp, zipFileParent.c_str(), loadAll))
romsFound[romIdx] = 1; // success! mark as loaded
}
}
// Ensure all ROMs were loaded
if (loadAll)
{
// See if any ROMs (that are not optional) could not be found
err = OKAY;
for (size_t i = 0; i < numROMs; i++)
{
if (!(romsFound[i] || Game->ROM[i].optional)) // if ROM not found and also not optional
err = ErrorLog("Could not load '%s' (CRC=%08X) from '%s'%s.", Game->ROM[i].fileName, Game->ROM[i].crc, zipFile, zfp ? zfpErr.c_str() : "");
}
}
else
err = OKAY;
Quit:
unzClose(zf);
delete [] buf;
return (err == OKAY) ? Game : NULL;
}

View file

@ -1,120 +0,0 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski, Nik Henson
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* ROMLoad.h
*
* Header file for ROM loading functions.
*/
#ifndef INCLUDED_ROMLOAD_H
#define INCLUDED_ROMLOAD_H
#include <cstdint>
/******************************************************************************
Data Structures
******************************************************************************/
/*
* ROMInfo:
*
* Describes a single ROM file.
*/
struct ROMInfo
{
// Function
const char *region; // ROM region identifier (used as a key to search ROMMap)
bool optional; // whether needs to be present or not
// Information used to identify files
const char *fileName; // file name
uint32_t crc; // CRC-32 checksum (same as zip format)
unsigned fileSize; // file size in bytes (must be the same as all other ROMs with same region ID)
// Interleaving information
unsigned groupSize; // number of consecutive bytes to fetch each time (groupSize%2 must = 0, must be consistent for region)
unsigned offset; // starting offset within ROM region
unsigned stride; // number of bytes to skip before loading next group of bytes from file (must be >= groupSize)
bool byteSwap; // swap every pair of bytes if true
};
/*
* ROMMap:
*
* Describes how to map ROM regions (where to load them). This structure is
* assembled after memory allocation is completed and tells the ROM loading
* functions where to load files by matching region identifiers with memory
* pointers.
*
* Both pointers must be set to NULL to terminate an array of ROM maps.
*/
struct ROMMap
{
const char *region; // ROM region identifier
uint8_t *ptr; // pointer to memory region
};
/******************************************************************************
Functions
******************************************************************************/
/*
* CopyRegion(dest, destOffset, destSize, src, srcSize):
*
* Repeatedly mirror (copy) to destination from source until destination is
* filled.
*
* Parameters:
* dest Destination region.
* destOffset Offset within destination to begin mirroring to.
* destSize Size in bytes of destination region.
* src Source region to copy from.
* srcSize Size of region to copy from.
*/
extern void CopyRegion(uint8_t *dest, unsigned destOffset, unsigned destSize, uint8_t *src, unsigned srcSize);
/*
* LoadROMSetFromZIPFile(Map, GameList, zipFile):
*
* Loads a complete ROM set from a zip archive. Automatically detects the game.
* If multiple games exist within the archive, an error will be printed and all
* but the first detected game will be ignored.
*
* Parameters:
* Map A list of pointers to the memory buffers for each ROM
* region.
* GameList List of all supported games and their ROMs.
* zipFile ZIP file to load from.
* loadAll If true, will check to ensure all ROMs were loaded.
* Otherwise, omits this check and loads only specified
* regions.
*
* Returns:
* Pointer to GameInfo struct for loaded game if successful, NULL
* otherwise. Prints errors.
*/
extern const struct GameInfo * LoadROMSetFromZIPFile(const struct ROMMap *Map, const struct GameInfo *GameList, const char *zipFile, bool loadAll);
#endif // INCLUDED_ROMLOAD_H

View file

@ -111,9 +111,6 @@
here, except for external packages and APIs.
******************************************************************************/
#include "Games.h"
#include "ROMLoad.h"
#include "INIFile.h"
#include "BlockFile.h"
#include "Graphics/New3D/New3D.h"
#include "Graphics/Render2D.h"