/*
 * Copyright (c) 2021-2023 Rupert Carmichael
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include "cega.h"
#include "cega_db.h"
#include "cega_sg.h"
#include "cega_sms.h"

typedef struct _dbentry_t {
    const char *md5;
    int mapper;
    uint32_t flags;
} dbentry_t;

static const dbentry_t db_gg[] = {
    // CJ Elephant Fugitive (Europe)
        { "30d140cba0604578382cff96aca09f78", SMS_MAPPER_CM, 0 },
    // Castle of Illusion Starring Mickey Mouse (USA, Europe)
        { "16b6ea96908c17d4389a5907710a0f4e", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
    // Cosmic Spacehead (Europe)
        { "0ad508b2a076990b49ae2bcda0f1e9e7", SMS_MAPPER_CM, 0 },
    // Dropzone (Europe)
        { "65df09530f9c8f02ab11982228d7d18e", SMS_MAPPER_CM, 0 },
    // Ernie Els Golf (Europe) (En,Fr,De,Es,It)
        { "e97c20b86ea73248cc7aed602d46c3a4", SMS_MAPPER_CM, 0 },
    // Excellent Dizzy Collection, The (Europe)
        { "613376b7b53e43ba17ae1b62da3c9251", SMS_MAPPER_CM, GG_DB_SMSMODE },
    // Fantastic Dizzy (Europe) (En,Fr,De,Es,It)
        { "66a8e3133a047fa7d44968efd3c30720", SMS_MAPPER_CM, GG_DB_SMSMODE },
    // Global Golf (Proto)
        { "022cfa638256560c60b4bcb292c63246", SMS_MAPPER_CM, 0 },
    // J.League GG Pro Striker '94 (Japan)
        { "d4034f6604c5dc04ee06e78b913c47fc", SMS_MAPPER_SEGA, DB_JP },
    // Jang Pung II (Korea) (Unl)
        { "9b95b6e6609daa8ea413f223f426c8ff", SMS_MAPPER_CM, GG_DB_SMSMODE },
    // Majors Pro Baseball, The (USA)
        { "b0c35bc53ab7c184d34e5624f69aad24", SMS_MAPPER_93C46, 0 },
    // Mickey Mouse no Castle Illusion (Japan)
        { "290056bcb4303d3c53ea7b6aa2a268a7", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
    // Micro Machines (Europe)
        { "c08b950e8ab836a737b07374f8235955", SMS_MAPPER_CM, 0 },
    // Micro Machines 2 - Turbo Tournament (Europe)
        { "4ed897e5e2bd76cbe92cbbbd76ac8817", SMS_MAPPER_CM, 0 },
    // Olympic Gold (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv) (Rev 1)
        { "59e311b86223273016a1e70b9c881af2", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
    // Olympic Gold (Japan, USA) (En,Fr,De,Es,It,Nl,Pt,Sv)
        { "d52c5db48882c0c126572a0cdeb5f472", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
    // Out Run Europa (Europe)
        { "bf5bd4d774600a866c2620e101845de8", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
    // Out Run Europa (USA)
        { "2a3bdd1a6c35eeedbf1a794abfb57b87", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
    // Pete Sampras Tennis (Europe)
        { "8a033a243a35fef96e6ea99584fe1755", SMS_MAPPER_CM, 0 },
    // Pete Sampras Tennis (USA)
        { "3bdd231599049c1f0c4b5e1344e8f5ca", SMS_MAPPER_CM, 0 },
    // Pop Breaker (Japan)
        { "e0e2fbd5834c04574795c923b0147f39", SMS_MAPPER_SEGA, DB_JP },
    // Predator 2 (USA, Europe)
        { "886649dc63aca898ce30a32348192cd5", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
    // Prince of Persia (USA, Europe)
        { "0d636c8d86dafd4f2c337e34e94b1e41", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
    // Prince of Persia (USA, Europe) (Beta)
        { "197e31dcafea7023cc948fea29c50230", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
    // Pro Yakyuu GG League (Japan)
        { "527449bc2aac2c8a16853fac63e60af6", SMS_MAPPER_93C46, 0 },
    // R.C. Grand Prix (USA, Europe)
        { "d087b25d96f3f3e9338b0b5ec4fc2aa5", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
    // Rastan Saga (Japan)
        { "fd82af26ebbed24f57c4eea8eddf3136", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
    // S.S. Lucifer - Man Overboard! (Europe)
        { "d369dcc7c7317b88d401cd7dd54ad951", SMS_MAPPER_CM, 0 },
    // Street Hero (USA) (Proto 1)
        { "56d261c2c0515d9621a73541e3d6aeae", SMS_MAPPER_CM, GG_DB_SMSMODE },
    // Street Hero (USA) (Proto 2)
        { "4290e4e83d37b142e39b2b0ad1366a8c", SMS_MAPPER_CM, GG_DB_SMSMODE },
    // Super Kick Off (Japan)
        { "91ab09b8b4d25a08dd0ebe13003e54b5", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
    // Taito Chase H.Q. (Japan)
        { "3cd1a4c27e330bba7703ee22ac83b856", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
    // Taito Chase H.Q. (USA)
        { "c72556c76d431b545dd56bdcc536a89f", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
    // World Series Baseball '95 (USA)
        { "e7eabbfc7a1f1339c4720249aea92a32", SMS_MAPPER_93C46, 0 },
    // World Series Baseball (USA) (Rev 1)
        { "05cac33029f0caac27774504c1aa8597", SMS_MAPPER_93C46, 0 },
    // World Series Baseball (USA)
        { "59359fc38865cff00c90d6eb148ddc2f", SMS_MAPPER_93C46, 0 },
    // WWF Wrestlemania Steel Cage Challenge (Europe)
        { "93e08b96e19eb89c6ba7e2bf3824c990", SMS_MAPPER_SEGA, GG_DB_SMSMODE },
};

static const dbentry_t db_md[] = {
    // Street Racer (Europe)
        { "c2967c23e72387743911bb28beb6f144", 0, DB_PAL },
};

static const dbentry_t db_sg[] = {
    // Adventure Island (Taiwan) (DahJee)
        { "a339edbd801c6f8edb4f0d220ef7208f", SG_MAPPER_TWMSXA, 0 },
    // Bomberman Special (Taiwan)
        { "25044d56bc18ad8b66a726c2f9d0b26b", SG_MAPPER_TWMSXB, 0 },
    // Bomberman Special (Taiwan) (DahJee)
        { "cd87c1a8cd8bc137673a7fb057e2142e", SG_MAPPER_TWMSXA, 0 },
    // Castle, The (Japan)
        { "d047c10d6b27cf34ccb66340a089523a", SG_MAPPER_RAM8K, 0 },
    // Castle, The (Taiwan) (MSX)
        { "a85ec287bb4151875446c245750fb8c0", SG_MAPPER_TWMSXB, 0 },
    // King's Valley (Taiwan)
        { "ff28e684eb3952ae3f7cf3e3d1c507ef", SG_MAPPER_TWMSXA, 0 },
    // Knightmare (Taiwan)
        { "e0321cd713ec1b48ff88f7df13e3ce28", SG_MAPPER_TWMSXA, 0 },
    // Legend of Kage, The (Taiwan)
        { "cfc8e61f51388609421ffe87539cad44", SG_MAPPER_TWMSXA, 0 },
    // Magical Kid Wiz (Taiwan)
        { "c12474e0a2556adb2478bc4d99faba51", SG_MAPPER_TWMSXB, 0 },
    // Othello (Japan)
        { "3f429704761d34d7793e7123a183d7f6", SG_MAPPER_RAM2K, 0 },
    // Othello (Taiwan)
        { "aa741b3264ee312c291b2c8ab0d73a04", SG_MAPPER_RAM2K, 0 },
    // Pippols (Taiwan)
        { "2b99db5c8a7a9a45c174088bab310803", SG_MAPPER_TWMSXA, 0 },
    // Rally-X (Taiwan)
        { "42f2844dcc4b3979b7f538ef9f52e4a5", SG_MAPPER_TWMSXB, 0 },
    // Rally-X (Taiwan) (DahJee)
        { "3071f939aaa0911fc0907aae5daaa160", SG_MAPPER_TWMSXA, 0 },
    // Road Fighter (Taiwan)
        { "be975a2510125ff4b545bb162826ef26", SG_MAPPER_TWMSXB, 0 },
    // Road Fighter (Taiwan) (Jumbo)
        { "e872bbe06fcee32e53fb9e11b61fe762", SG_MAPPER_TWMSXA, 0 },
    // Star Soldier (Taiwan)
        { "cb95017c8d13d95c91129f9b3b1f6798", SG_MAPPER_TWMSXA, 0 },
    // Tank Battalion (Taiwan)
        { "dada9d76f7743089811dcc8ec1543076", SG_MAPPER_TWMSXA, 0 },
    // Terebi Oekaki (Japan)
        { "be31a84bfa537117a62eaeb8c0a07bf9", SG_MAPPER_TEREBI, SG_DB_TEREBI },
    // The Goonies (Taiwan) (DahJee)
        { "f072323018565c2d08a612c9ff03b73f", SG_MAPPER_TWMSXA, 0 },
    // TwinBee (Taiwan)
        { "8c2c0d7e8415ae7b0c577cf947e89e78", SG_MAPPER_TWMSXA, 0 },
    // Yie Ar Kung-Fu II (Taiwan)
        { "c1f51f5dbfb859b1204a812d9c08ffd3", SG_MAPPER_TWMSXA, 0 },
    // Zanac (Taiwan) (DahJee)
        { "87d801ae4164fb286fd7a0a27bd3d13c", SG_MAPPER_TWMSXA, 0 }
};

static const dbentry_t db_sms[] = {
    // BIOS Images
    // Alex Kidd in Miracle World (Korea) (Unl)
        { "e49e63328c78fe3d24ae32bf903583e0", SMS_MAPPER_BIOS, DB_JP },
    // Alex Kidd in Miracle World (USA, Europe)
        { "e8b26871629b938887757a64798df6dc", SMS_MAPPER_BIOS, 0 },
    // Hang On & Safari Hunt (USA, Europe, Brazil) (v2.4)
        { "02cbb2e348945c9ac41e37502a58ca76", SMS_MAPPER_BIOS, 0 },
    // Hang On (USA, Europe) (v3.4)
        { "5cd8f62cd8786af0226e6d2248279338", SMS_MAPPER_BIOS, 0 },
    // Missile Defense 3-D (USA, Europe) (v4.4)
        { "08b81aa6be18b92daef1b875deecf824", SMS_MAPPER_BIOS, 0 },
    // Sega Master System (Europe) (v2.0)
        { "bdb34f2c471e5d0c358eeec621f9d029", SMS_MAPPER_BIOS, DB_PAL },
    // Sega Master System (Japan) (v2.1)
        { "24a519c53f67b00640d0048ef7089105", SMS_MAPPER_BIOS, DB_JP },
    // Sega Master System (USA) (M404) (Proto)
        { "3153447d155fb8bfc66a4d1c41e399b9", SMS_MAPPER_BIOS, 0 },
    // Sega Master System (USA) (Store Display Unit)
        { "b264bef9bda264ffe83afcebac21b81f", SMS_MAPPER_BIOS, 0 },
    // Sega Master System (USA, Europe) (v1.3)
        { "840481177270d5642a14ca71ee72844c", SMS_MAPPER_BIOS, 0 },
    // Sonic The Hedgehog (Europe)
        { "4187d96beaf36385e681a3cf3bd1663d", SMS_MAPPER_BIOS, DB_PAL },

    // No Mapper
    // C_So! (Korea) (Unl)
        { "dd0b6a4f11018ff3d2e6a2b9d9888576", SMS_MAPPER_NONE, 0 },
    // Eagles 5 (Korea) (Unl)
        { "93a96c1aa540cd65dc8be69a7b074edc", SMS_MAPPER_NONE, 0 },
    // FA Tetris (Korea) (Unl)
        { "f3d0d07a2eea23175d9a8d2b428151e8", SMS_MAPPER_NONE, 0 },
    // Flashpoint (Korea) (Unl)
        { "e74328c8cdd71af02ed99b17139126cd", SMS_MAPPER_NONE, 0 },
    // Hong Kil Dong (Korea)
        { "372b7edf08f3bc235ef5351c116e5c9b", SMS_MAPPER_NONE, 0 },
    // MSX Soccer (KR)
        { "595e3e6fa6342dd346830c1d6b5b3636", SMS_MAPPER_NONE, 0 },
    // Sky Jaguar (Korea) (Clover) (Unl)
        { "19a825bd9210ce0ff84cb883c750e7fc", SMS_MAPPER_NONE, 0 },
    // Sky Jaguar (Korea) (Unl)
        { "836d0b4c9ab9296cc78a5f8e2cb375d7", SMS_MAPPER_NONE, 0 },
    // Super Boy II (Korea) (Unl)
        { "6120c9ba0f2c24031c9a836035060717", SMS_MAPPER_NONE, 0 },
    // Three Dragon Story, The (Korea) (Unl)
        { "9acd8b2eab5453380242ab3a6417c165", SMS_MAPPER_NONE, 0 },
    // Xyzolog (Korea)
        { "21b563031bb035f117d15dc53f406c2d", SMS_MAPPER_NONE, 0 },

    // Codemasters Mapper
    // Cosmic Spacehead (Europe) (En,Fr,De,Es)
        { "7debf96f69c896d8571a6ad6cfacf502", SMS_MAPPER_CM, DB_PAL },
    // Dinobasher Starring Bignose the Caveman (Europe) (Proto)
        { "bb448ca5ce1ec7d86636c6571d6e94cb", SMS_MAPPER_CM, 0 },
    // Excellent Dizzy Collection, The (USA, Europe) (En,Fr,De,Es,It) (Proto)
        { "c68b86706784801eff53a4ca4500ff21", SMS_MAPPER_CM, DB_PAL },
    // Fantastic Dizzy (Europe) (En,Fr,De,Es,It)
        { "b8eb0cb6a9d16cfd08d9c03297fcd445", SMS_MAPPER_CM, DB_PAL },
    // Micro Machines (Europe)
        { "a90cf8d68fa8b1f0ba00f0ddb9d547b7", SMS_MAPPER_CM, DB_PAL },

    // Janggun Mapper (Korea8K, Korea2)
    // Janggun-ui Adeul (Korea)
        { "2db7aaabca7f62d69df466797c0d63d9", SMS_MAPPER_JANGGUN, 0 },

    // Korea Mapper
    // Dallyeora Pigu-Wang (Korea) (Unl)
        { "3ad7b3e23400ee10b7239e22d45aca4e", SMS_MAPPER_KOREA, 0 },
    // Jang Pung 3 (Korea) (Unl)
        { "f355ec9d0171a4d01356165d2baba6a1", SMS_MAPPER_KOREA, 0 },
    // Jang Pung II (Korea) (Unl)
        { "c67c5f04519000394bd525eccb774958", SMS_MAPPER_KOREA, 0 },
    // Sangokushi 3 (Korea) (Unl)
        { "517c371a929ab012ee95a20843c5f1c2", SMS_MAPPER_KOREA, 0 },

    // MSX Mapper
    // Cyborg Z (Korea)
        { "0027ab3b7479cb1385e43d1f41bcddd6", SMS_MAPPER_MSX, 0 },
    // F-1 Spirit - The Way to Formula-1 (Korea) (Unl) (Pirate)
        { "293ef0398970cff0a5b4cd419b643f3c", SMS_MAPPER_MSX, 0 },
    // Knightmare II - The Maze of Galious (Korea)
        { "09d622effa934695566e47f1fb1d4b77", SMS_MAPPER_MSX, 0 },
    // Nemesis 2 (Korea)
        { "f6b084c626d96f4d48203caaed0ae6b1", SMS_MAPPER_MSX, 0 },
    // Penguin Adventure (Korea) (Unl) (Pirate)
        { "cada8fbd55b6444f2308e770c79eaccc", SMS_MAPPER_MSX, 0 },
    // Street Master (Korea) (Unl)
        { "ea83395c811ab1e40e9f3f6b47908ae7", SMS_MAPPER_MSX, 0 },
    // Super Boy III (Korea) (Unl)
        { "ca1e0e7bdd2a0be70129b1de97746e40", SMS_MAPPER_MSX, 0 },
    // Wonsiin (Korea) (Pirate)
        { "c53091e60b5bd473142ca231dd96f6eb", SMS_MAPPER_MSX, 0 },

    // Nemesis Mapper (MSX Mapper Variant)
    // Nemesis (Korea)
        { "1f9b5ae214384c15e43e1d8eee00c31f", SMS_MAPPER_NEMESIS, 0 },

    // 4 PAK All Action Mapper
    // 4 PAK All Action (Australia) (Unl)
        { "4ea64e3b2ad57ef7531890583c51de30", SMS_MAPPER_4PAA, 0 },

    // X in 1 Mapper
    // 3 in 1 - The Best Game Collection (A) (Korea) (Unl)
        { "bf7609929bcc2856a92bf35a5a480225", SMS_MAPPER_XIN1, 0 },
    // 3 in 1 - The Best Game Collection (B) (Korea) (Unl)
        { "2949e35216ce3b36ce26af35b80db73a", SMS_MAPPER_XIN1, 0 },
    // 3 in 1 - The Best Game Collection (C) (Korea) (Unl)
        { "86559e1ba9225d7caaf86bb412e9a8b7", SMS_MAPPER_XIN1, 0 },
    // 3 in 1 - The Best Game Collection (D) (Korea) (Unl)
        { "02662af5700ba779e1739f24bf08bf77", SMS_MAPPER_XIN1, 0 },
    // 3 in 1 - The Best Game Collection (E) (Korea) (Unl)
        { "5e23d4771c1f6ffa0de8e3632e822f38", SMS_MAPPER_XIN1, 0 },
    // 3 in 1 - The Best Game Collection (F) (Korea) (Unl)
        { "1c921e5460b3c9928a3f83f8ce60ac39", SMS_MAPPER_XIN1, 0 },
    // 8 in 1 - The Best Game Collection (A) (Korea) (Unl)
        { "151a25c3909b75fbe674fc6cda85d9b4", SMS_MAPPER_XIN1, 0 },
    // 8 in 1 - The Best Game Collection (B) (Korea) (Unl)
        { "09855174b67e481b13fc13700017b6d5", SMS_MAPPER_XIN1, 0 },
    // 8 in 1 - The Best Game Collection (C) (Korea) (Unl)
        { "6c4729e7ac7b20746eba51ab16273945", SMS_MAPPER_XIN1, 0 },

    // Korean 2000 XOR 1F
    // 128 Hap (KR)
        { "6dddeb0bb21622b6ee1deb4c4870f801", SMS_MAPPER_KR_2000_XOR_1F, 0 },
    // Game Mo-eumjip 188 Hap (KR)
        { "733fd1ddf07de2d0ffca2c8048223493", SMS_MAPPER_KR_2000_XOR_1F, 0 },
    // Game Mo-eumjip 188 Hap (KR) [v1]
        { "ba730a6aa10317fdf460cc8b5ef80ee5", SMS_MAPPER_KR_2000_XOR_1F, 0 },

    // Korean MSX 8KB 0300
    // Game Chongjiphap 200 (KR)
        { "fea62e851df9525268d4a5a221315232", SMS_MAPPER_KR_MSX_8KB_0300, 0 },
    // Super Game World 30 Hap [v0] (KR)
        { "0691f169f7ac78d739dfe592b85560b9", SMS_MAPPER_KR_MSX_8KB_0300, 0 },
    // Super Game World 30 Hap [v1] (KR)
        { "08472554077a4b725b3ab7977c46883f", SMS_MAPPER_KR_MSX_8KB_0300, 0 },
    // Super Game World 75 Hap (KR)
        { "1ba64ddcd0daa6a21876b41d42d355d3", SMS_MAPPER_KR_MSX_8KB_0300, 0 },
    // Super Multi Game - Super 125 in 1 (KR)
        { "54f51d172f6dbcfde0d0875b13ff2429", SMS_MAPPER_KR_MSX_8KB_0300, 0 },
    // Super Multi Game - Super 75 in 1 (KR)
        { "f82a33475aac9465aebcd2a850ea1558", SMS_MAPPER_KR_MSX_8KB_0300, 0 },

    // Korean BFFC
    // Super Game 52 Hap (KR)
        { "8b409b5f4a5dc0a79ed3593a8cd6f8db", SMS_MAPPER_KR_BFFC, 0 },
    // Super Game 180 (KR)
        { "b56ff1402af91fb18024123c529aebee", SMS_MAPPER_KR_BFFC, 0 },

    // Korean FFFE
    // Super Game 45 Hap (KR)
        { "9151e794b1507d76d68797271a90b623", SMS_MAPPER_KR_FFFE, 0 },

    // Korean FFF5
    // Pigu-Wang 7 Hap - Jaemiiss-neun Game Mo-eumjip (KR)
        { "286e0674b6221fc3dc8d92817d16a765", SMS_MAPPER_KR_FFF5, 0 },

    // Korean MSX 32KB 2000
    // 2 Hap in 1 (Moai-ui bomul, David-2) (KR)
        { "2a9a931d555471c765b7359b2559345f", SMS_MAPPER_KR_MSX_32KB_2000, 0 },

    // Korean 0000 XOR FF
    // Zemina 4-in-1 (Q-Bert, Sports 3, Gulkave, Pooyan) (KR)
        { "2ff0a657904967da235d56b70b15ecff", SMS_MAPPER_KR_0000_XOR_FF, 0 },

    // Korean MSX/SMS 8000 Mapper
    // Zemina Best 25 (KR)
        { "0c9c2d8c13fe9a5c29bea8cf8c419c96", SMS_MAPPER_KR_MSX_SMS_8000, 0 },
    // Zemina Best 39 (KR)
        { "311fe2bf0505f83f3f563e2e7498fede", SMS_MAPPER_KR_MSX_SMS_8000, 0 },
    // Zemina Best 88 (KR)
        { "fd63e6a8410a61b733973668c768efc0", SMS_MAPPER_KR_MSX_SMS_8000, 0 },

    // Korean FFF3/FFFC Mapper
    // Super Game 150 (KR)
        { "096055cb99481e0b296daf9a65d30154", SMS_MAPPER_KR_FFF3_FFFC, 0 },

    // Korean SMS 32KB 2000
    // 11 Hap Gam-Boy (KR)
        { "671bd01471569345147e37b8c6c6e6f8", SMS_MAPPER_KR_SMS_32KB_2000, 0 },

    // MSX Generic 16 8000 Mapper
    // Wonder Kid [Proto] [SMS-GG]
    // NOTE: Dump is from a GG cartridge, but does not work in SMS-GG mode
        { "cf9c266298c0a5209da9d2a7d8850d15", SMS_MAPPER_MSX_GNRC16_8000, 0},

    // Paddle
    // BMX Trial - Alex Kidd (Japan)
        { "571f18f49e679a128b4a237001760d6c", SMS_MAPPER_SEGA,
            SMS_DB_PADDLE | DB_JP },
    // Galactic Protector (Japan)
        { "8d61b59296877216cf7e4b04a68bfa66", SMS_MAPPER_SEGA,
            SMS_DB_PADDLE | DB_JP },
    // Megumi Rescue (Japan)
        { "fd834dbb87682c674f7d7ed917355021", SMS_MAPPER_SEGA,
            SMS_DB_PADDLE | DB_JP },
    // Woody Pop - Shinjinrui no Block Kuzushi (Japan)
        { "1b1b6051027806a98e9947b5ae5f0076", SMS_MAPPER_SEGA,
            SMS_DB_PADDLE | DB_JP },

    // Light Phaser
    // 3D Gunner (USA) (Demo)
        { "486dea48606666b44c7e6db9d7a1454c", SMS_MAPPER_SEGA, SMS_DB_PHASER },
    // Assault City (Europe) (Light Phaser)
        { "4354119b151d9129d31918865db9b1c9", SMS_MAPPER_SEGA, SMS_DB_PHASER },
    // Gangster Town (USA, Europe)
        { "3396259ca032ed4f1499d1f737e75e0d", SMS_MAPPER_SEGA,
            SMS_DB_PHASER | SMS_DB_PHOFFSET },
    // Hang-On & Safari Hunt (USA)
        { "84284c327b07c200c16f4e13b2e8de79", SMS_MAPPER_SEGA, SMS_DB_PHASER },
    // Hang-On & Safari Hunt (USA) (Beta)
        { "16d870bf1a5a23a9f2993d8786f5bc74", SMS_MAPPER_SEGA, SMS_DB_PHASER },
    // Laser Ghost (Europe)
        { "17f9c50c444dc94e08ba173ab306608b", SMS_MAPPER_SEGA,
            SMS_DB_PHASER | DB_PAL },
    // Marksman Shooting & Trap Shooting & Safari Hunt (Europe)
        { "bf7ea79ac0df3ebe7256da6331b21c34", SMS_MAPPER_SEGA, SMS_DB_PHASER },
    // Marksman Shooting & Trap Shooting (USA, Brazil)
        { "0a28cfd7b151531fb7a43181c24e1d3d", SMS_MAPPER_SEGA, SMS_DB_PHASER },
    // Missile Defense 3-D (USA, Europe, Brazil)
        { "b17ca24555cc79c5f7d89f156b99e452", SMS_MAPPER_SEGA, SMS_DB_PHASER },
    // Missile Defense 3-D (USA, Europe, Brazil) (Sample)
        { "6c3d54e1338112fd39418ca8da672994", SMS_MAPPER_SEGA, SMS_DB_PHASER },
    // Missile Defense 3-D (USA, Europe) (v4.4)
        { "08b81aa6be18b92daef1b875deecf824", SMS_MAPPER_SEGA, SMS_DB_PHASER },
    // Operation Wolf (Europe)
        { "2ca2064302f51f724e1f2593369a0696", SMS_MAPPER_SEGA,
            SMS_DB_PHASER | DB_PAL},
    // Rambo III (USA, Europe)
        { "4fce4e3247639d0ef54eb54d0ef21153", SMS_MAPPER_SEGA, SMS_DB_PHASER },
    // Rescue Mission (USA, Europe)
        { "717fdf868c8f11a712697260eb7db670", SMS_MAPPER_SEGA, SMS_DB_PHASER },
    // Shooting Gallery (USA, Europe)
        { "f8ea8b8e641cabff32210ea6583f9f94", SMS_MAPPER_SEGA, SMS_DB_PHASER },
    // Space Gun (Europe)
        { "ebb0b4161ffa873a7fa80ca41d139c57", SMS_MAPPER_SEGA,
            SMS_DB_PHASER | SMS_DB_PHOFFSET },
    // Wanted (USA, Europe)
        { "0070737ddb0a2e5e822f1d8f46437b07", SMS_MAPPER_SEGA,
            SMS_DB_PHASER | SMS_DB_FMDISABLE },

    // Sports Pad
    // Great Ice Hockey (Japan, USA)
        { "374d762b51b1c5ea8ff7903f98586e0e", SMS_MAPPER_SEGA, SMS_DB_SPORTS },
    // Great Ice Hockey (Japan, USA) (Alternate)
        { "26621293a88d55fedaf71bb097c24653", SMS_MAPPER_SEGA, SMS_DB_SPORTS },
    // Sports Pad Football (USA)
        { "3317f644f36159e2dc63aea9b75c927d", SMS_MAPPER_SEGA, SMS_DB_SPORTS },
    // Sports Pad Soccer (Japan)
        { "4cc5ba7ef736508a8afc1ed7ec640c3e", SMS_MAPPER_SEGA, SMS_DB_SPORTS },

    // Sega Mapper games that only work correctly in the Japanese region
    // OutRun (World) - (FM Audio, JP region needed to avoid PSG artifacts)
        { "029ee92155247f8a282d63b8a6dd23c4", SMS_MAPPER_SEGA, DB_JP },
    // Super Arkanoid (Korea) (Unl)
        { "8daab9ac07e896995c3454ff92de6480", SMS_MAPPER_SEGA, DB_JP },
    // Wonder Boy III - The Dragon's Trap (USA, Europe) - (FM Audio)
        { "e7f86c049e4bd8b26844ff62bd067d57", SMS_MAPPER_SEGA, DB_JP },

    // Sega Mapper games that only work correctly in PAL Mode
    // Addams Family, The (Europe)
        { "09202bc26fcf19ebd3ffcbd80e23ed9d", SMS_MAPPER_SEGA, DB_PAL },
    // Always Continue (Rick Astley Demo)
        { "31c0d0cddf460a87855c9ecc960ee11b", SMS_MAPPER_SEGA, DB_PAL },
    // Back to the Future Part II (Europe, Brazil)
        { "f2535df9bdc3a84221303fa62d61ad6e", SMS_MAPPER_SEGA, DB_PAL },
    // Back to the Future Part III (Europe)
        { "3d24a52e98e6c85d7c059386451ce749", SMS_MAPPER_SEGA, DB_PAL },
    // Be No Sqr (Demo)
        { "ad112e000120b2d2f31bd49b009c818b", SMS_MAPPER_SEGA, DB_PAL },
    // Bram Stoker's Dracula (Europe)
        { "4b3c934b3daa99a6b341da57388a7543", SMS_MAPPER_SEGA, DB_PAL },
    // California Games II (Europe)
        { "5ac58b3a7fda23161ab1185b3ee797ac", SMS_MAPPER_SEGA, DB_PAL },
    // Desert Strike (Europe) (En,Fr,De,Es)
        { "df89aa1ebc5f42db21fb8d12d9e78511", SMS_MAPPER_SEGA, DB_PAL },
    // GP Rider - (Questionable)
        { "1af1cdf8d40c305f936e72b51cb4740d", SMS_MAPPER_SEGA, DB_PAL },
    // Home Alone (Europe)
        { "b0100ad9f1838332b15d0434bfa9fe29", SMS_MAPPER_SEGA, DB_PAL },
    // James Bond 007 - The Duel (Europe)
        { "c52e496c497d427747769aaedfbb8dab", SMS_MAPPER_SEGA, DB_PAL },
    // Jungle Book, The (Europe, Brazil)
        { "ed224898befb4fb246175e46f9982821", SMS_MAPPER_SEGA, DB_PAL },
    // NBA Jam (Europe) (Proto)
        { "3d847bf62567026be23512961a578063", SMS_MAPPER_SEGA, DB_PAL },
    // NewZealand Story, The (Europe)
        { "05e5054e2ea818d4b7eb53d624562dcf", SMS_MAPPER_SEGA, DB_PAL },
    // Predator 2 (Europe)
        { "1389419d90834d3700b772e984143fde", SMS_MAPPER_SEGA, DB_PAL },
    // RoboCop 3 (Europe, Brazil)
        { "c656dc9f901387cc51276e4709c340f8", SMS_MAPPER_SEGA, DB_PAL },
    // Sensible Soccer (Europe)
        { "5ca0a2b33db8eedcddb1d5aeaa8ea5a4", SMS_MAPPER_SEGA, DB_PAL },
    // Shadow of the Beast (Europe, Brazil)
        { "abc8a9e43c588c7d0535cc8305bdbf94", SMS_MAPPER_SEGA, DB_PAL },
    // Simpsons, The - Bart vs. the Space Mutants (Europe, Brazil)
        { "26df4404950cb8da47235833c0c101c6", SMS_MAPPER_SEGA, DB_PAL },
    // Sonic The Hedgehog 2 (Europe, Brazil)
        { "bf3b7a41e7da9de23416473a33c6ac2b", SMS_MAPPER_SEGA, DB_PAL },
    // Sonic The Hedgehog 2 (Europe, Brazil) (Rev 1)
        { "0ac157b6b7e839953fc8eba7538fb74a", SMS_MAPPER_SEGA, DB_PAL },
    // Taito Chase H.Q. (Europe)
        { "08511c5cf0df0941b10ebf28050afe51", SMS_MAPPER_SEGA, DB_PAL },
    // Taito Chase H.Q. (Europe) (Beta)
        { "b8fb4d18b555cb496f2f6243f0688486", SMS_MAPPER_SEGA, DB_PAL },
    // Winter Olympics (Brazil) (En,Fr,De,Es,It,Pt,Sv,No)
        { "d3bcf99a883e14a2f9df8dd92662710f", SMS_MAPPER_SEGA, DB_PAL },
    // Winter Olympics (Europe) (En,Fr,De,Es,It,Pt,Sv,No)
        { "6046d9ee439f3c76eb6713eea8ba984b", SMS_MAPPER_SEGA, DB_PAL },
    // Xenon 2 - Megablast (Europe)
        { "1f1ce1d74c416f2b85cc3f24d316f9e3", SMS_MAPPER_SEGA, DB_PAL },
    // Xenon 2 - Megablast (Europe) (Rev 1)
        { "27fba4b7db989c663dda11c255cf49f3", SMS_MAPPER_SEGA, DB_PAL },

    // Games requiring SMS1 VDP behaviour
    // Scramble Spirits [Proto]
        { "424308c465d676d3dca05bd0410798c2", SMS_MAPPER_SEGA, SMS_DB_SMS1VDP },
    // Ys (Japan)
        { "17364162da3ccee847850dd9b403765c", SMS_MAPPER_SEGA, SMS_DB_SMS1VDP },
    // Ys - The Vanished Omens (USA, Europe) (Demo)
        { "1fb26de7fe25803778cdc0391c7fb66f", SMS_MAPPER_SEGA, SMS_DB_SMS1VDP },

    // Games requiring the VDP Frame Interrupt set on boot
    // Sonic's Edusoft (Unknown) (Proto)
        { "5919b101624d4710a10825c34e753ba2", SMS_MAPPER_SEGA, SMS_DB_FRINT }
};

uint32_t cega_db_process_gg(const char *md5) {
    // Loop through the database and compare the MD5 checksum
    for (size_t i = 0; i < (sizeof(db_gg) / sizeof(dbentry_t)); ++i) {
        if (!strcmp(md5, db_gg[i].md5)) {
            cega_sms_set_mapper(db_gg[i].mapper);
            return db_gg[i].flags;
        }
    }

    cega_sms_set_mapper(SMS_MAPPER_SEGA);
    return 0;
}

uint32_t cega_db_process_md(const char *md5) {
    // Loop through the database and compare the MD5 checksum
    for (size_t i = 0; i < (sizeof(db_md) / sizeof(dbentry_t)); ++i) {
        if (!strcmp(md5, db_md[i].md5)) {
            return db_md[i].flags;
        }
    }

    return 0;
}

uint32_t cega_db_process_sg(const char *md5) {
    // Loop through the database and compare the MD5 checksum
    for (size_t i = 0; i < (sizeof(db_sg) / sizeof(dbentry_t)); ++i) {
        if (!strcmp(md5, db_sg[i].md5)) {
            // Match found - set the appropriate mapper and return the flags
            cega_sg_set_mapper(db_sg[i].mapper);
            return db_sg[i].flags;
        }
    }

    return 0;
}

uint32_t cega_db_process_sms(const char *md5) {
    // Loop through the database and compare the MD5 checksum
    for (size_t i = 0; i < (sizeof(db_sms) / sizeof(dbentry_t)); ++i) {
        if (!strcmp(md5, db_sms[i].md5)) {
            // Match found - set the appropriate mapper and return the flags
            cega_sms_set_mapper(db_sms[i].mapper);

            if (db_sms[i].mapper == SMS_MAPPER_BIOS)
                cega_sms_set_bios(0x03);

            return db_sms[i].flags;
        }
    }

    // If nothing was found, default to the Sega Mapper and no flags
    cega_sms_set_mapper(SMS_MAPPER_SEGA);
    return 0;
}
