Update cartdb, fix system IDs, change sorting criteria

This commit is contained in:
spicyjpeg 2023-09-23 18:37:55 +02:00
parent ada89001a5
commit 123c6fa14d
No known key found for this signature in database
GPG Key ID: 5CC87404C01DF393
7 changed files with 572 additions and 264 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -295,6 +295,29 @@ bool isValidRegion(const char *region) {
return true;
}
bool isValidUpgradeRegion(const char *region) {
if (!region[0] || !__builtin_strchr("aejksu", region[0]))
return false;
if (!region[1] || !__builtin_strchr("abcdefrstuvwxyz", region[1]))
return false;
if (region[2]) {
if (!__builtin_strchr("abcdz", region[2]))
return false;
if (region[2] == 'z') {
if (!__builtin_isdigit(region[3]) || !__builtin_isdigit(region[4]))
return false;
region += 2;
}
if (region[3])
return false;
}
return true;
}
Parser *newCartParser(Dump &dump, FormatType formatType, uint8_t flags) {
switch (formatType) {
case SIMPLE:

View File

@ -11,9 +11,10 @@ namespace cart {
/* Cartridge data parsers */
static constexpr size_t CODE_LENGTH = 5;
static constexpr size_t REGION_MIN_LENGTH = 2;
static constexpr size_t REGION_MAX_LENGTH = 5;
static constexpr size_t CODE_LENGTH = 5;
static constexpr size_t CODE_PREFIX_LENGTH = 2;
static constexpr size_t REGION_MIN_LENGTH = 2;
static constexpr size_t REGION_MAX_LENGTH = 5;
class Parser {
protected:
@ -100,6 +101,7 @@ public:
};
bool isValidRegion(const char *region);
bool isValidUpgradeRegion(const char *region);
Parser *newCartParser(Dump &dump, FormatType formatType, uint8_t flags = 0);
Parser *newCartParser(Dump &dump);
@ -118,7 +120,14 @@ public:
char code[8], region[8], name[96];
inline int compare(const char *_code, const char *_region) const {
int diff = __builtin_strncmp(code, _code, CODE_LENGTH + 1);
int diff = __builtin_strncmp(
&code[CODE_PREFIX_LENGTH], &_code[CODE_PREFIX_LENGTH],
CODE_LENGTH - CODE_PREFIX_LENGTH + 1
);
if (diff)
return diff;
diff = __builtin_strncmp(code, _code, CODE_PREFIX_LENGTH);
if (diff)
return diff;
@ -130,7 +139,7 @@ public:
inline bool requiresCartID(void) const {
if (flags & DATA_HAS_CART_ID)
return true;
if ((flags & DATA_HAS_TRACE_ID) && (traceIDType != TID_81))
if ((flags & DATA_HAS_TRACE_ID) && (traceIDType >= TID_82_BIG_ENDIAN))
return true;
return false;

View File

@ -383,10 +383,11 @@ class DBEntry:
else:
self.installIDPrefix = 0
# Implement the comparison overload so sorting will work.
# Implement the comparison overload so sorting will work. The 3-digit number
# in the game code is used as a key.
def __lt__(self, entry: Any) -> bool:
return ( self.code, self.region, self.name ) < \
( entry.code, entry.region, entry.name )
return ( self.code[2:], self.code[0:2], self.region, self.name ) < \
( entry.code[2:], entry.code[0:2], entry.region, entry.name )
def requiresCartID(self) -> bool:
if self.flags & DataFlag.DATA_HAS_CART_ID:

View File

@ -21,16 +21,18 @@ class GameEntry:
code: str
region: str
name: str
mameID: str
installCart: str | None = None
gameCart: str | None = None
ioBoard: str | None = None
mameID: str | None = None
installCart: str | None = None
gameCart: str | None = None
ioBoard: str | None = None
lockedToIOBoard: bool = False
# Implement the comparison overload so sorting will work.
# Implement the comparison overload so sorting will work. The 3-digit number
# in the game code is used as a key.
def __lt__(self, entry: Any) -> bool:
return ( self.code, self.region, self.name ) < \
( entry.code, entry.region, entry.name )
return ( self.code[2:], self.code[0:2], self.region, self.name ) < \
( entry.code[2:], entry.code[0:2], entry.region, entry.name )
def __str__(self) -> str:
return f"{self.code} {self.region}"
@ -56,11 +58,12 @@ class GameDB:
code: str = entryObj["code"].strip().upper()
region: str = entryObj["region"].strip().upper()
name: str = entryObj["name"]
mameID: str = entryObj["id"]
installCart: str | None = entryObj.get("installCart", None)
gameCart: str | None = entryObj.get("gameCart", None)
ioBoard: str | None = entryObj.get("ioBoard", None)
mameID: str | None = entryObj.get("id", None)
installCart: str | None = entryObj.get("installCart", None)
gameCart: str | None = entryObj.get("gameCart", None)
ioBoard: str | None = entryObj.get("ioBoard", None)
lockedToIOBoard: bool = entryObj.get("lockedToIOBoard", False)
if GAME_CODE_REGEX.fullmatch(code.encode("ascii")) is None:
raise ValueError(f"invalid game code: {code}")
@ -68,7 +71,8 @@ class GameDB:
raise ValueError(f"invalid game region: {region}")
entry: GameEntry = GameEntry(
code, region, name, mameID, installCart, gameCart, ioBoard
code, region, name, mameID, installCart, gameCart, ioBoard,
lockedToIOBoard
)
# Store all entries indexed by their game code and first two characters
@ -239,8 +243,10 @@ def processDump(
matches: list[GameEntry] = sorted(db.lookup(parser.code, parser.region))
if exportFile:
matchList: str = " ".join(game.mameID for game in matches)
_, flags = str(parser.flags).split(".", 1)
matchList: str = " ".join(
(game.mameID or f"[{game}]") for game in matches
)
exportFile.write(
f"{dump.chipType.name},{nameHint},{parser.code},{parser.region},"
@ -254,15 +260,17 @@ def processDump(
if game.hasCartID():
if not (parser.flags & DataFlag.DATA_HAS_CART_ID):
raise RuntimeError("dump has a cartridge ID but game does not")
raise RuntimeError("game has a cartridge ID but dump does not")
else:
if parser.flags & DataFlag.DATA_HAS_CART_ID:
raise RuntimeError("game has a cartridge ID but dump does not")
raise RuntimeError("dump has a cartridge ID but game does not")
if game.hasSystemID():
parser.flags |= DataFlag.DATA_HAS_SYSTEM_ID
if game.hasSystemID() and game.lockedToIOBoard:
if not (parser.flags & DataFlag.DATA_HAS_SYSTEM_ID):
raise RuntimeError("game has a system ID but dump does not")
else:
parser.flags &= ~DataFlag.DATA_HAS_SYSTEM_ID
if parser.flags & DataFlag.DATA_HAS_SYSTEM_ID:
raise RuntimeError("dump has a system ID but game does not")
logging.info(f"imported {dump.chipType.name}: {game.getFullName()}")
return DBEntry(parser.code, parser.region, game.name, dump, parser)