static string detectSoundDriver(ROMInfo info, byte[] bytes) { if (ByteSearch.contains(bytes, MP2K_SELECTSONG)) { //The standard driver among most GBA games, seemingly included in the official GBA SDK (apparently). Otherwise //known as Sappy or M4A return("MP2000"); } else if (ByteSearch.contains(bytes, MP2K_NEW_SELECTSONG)) { //Apparently it was also recompiled at some point and some games use it (Mother 3, Minish Cap, some others) but there doesn't seem to be any consistency in terms of new games using this and older games using the allegedly older driver return("MP2000 (new)"); } else if (ByteSearch.contains(bytes, NATSUME_MAIN)) { //Not sure what uses this. Games developed by Natsume, I guess (which amounts to basically Medabots, Keitai Denju Telefang 2, Buffy the Vampire Slayer, Shaun Palmer's Pro Snowboarder, some Power Rangers and wrestling games) return("Natsume"); } else if (ByteSearch.contains(bytes, KRAWALL_MIXCENTER)) { //A third party thing that plays converted s3m/xm files, used by a few games such as //Lord of the Rings and The Sims according to the author's website, and also //Dora the Explorer: Dora's World Adventure and Harry Potter and the Prisoner of Azkaban (but //not the other Dora or Harry Potter games), unless I'm actually detecting this all wrong //and they use something else. It's possible I am because it appears in a few homebrew //demos (excluding the obvious Krawall Demo), but then maybe they actually do use it since it's now LGPL'd //so I guess I should check the credits of those? return("Krawall"); } else if (ByteSearch.contains(bytes, RARE_AUDIO_ERROR)) { //Games developed by Rare have this huge block of error text. This is probably the most wrong way to //possibly do this but it works and whatnot so maybe it isn't. But I feel dirty for doing this return("Rare"); } else if (ByteSearch.contains(bytes, GAX2_INIT)) { //Used by various third-party games. All of them have a block of copyright text //specifying that the game uses the GAX engine, and also the version which is nice, that //the engine is developed by Shin'en Multimedia, and also some function names like //GAX2_INIT a bit after that block. Although I feel like this might result in //false positives.... should be fine, hopefully return("GAX"); } else if (ByteSearch.contains(bytes, LOGIK_STATE_COPYRIGHT)) { //I don't know what to call this one; used in a few third party games (Asterisk & Obelisk XXL, Driv3r among others) //Gotta admit I don't really like this and should detect it better, but it is apparent that those two games use things by this //company at least return("GBAModPlay/LS_Play"); } else { return("Unknown"); } }
static void detectSaveType(ROMInfo info, byte[] bytes) { if (ByteSearch.contains(bytes, EEPROM)) { info.addInfo("Save type", "EEPROM"); //Can't tell the save size from this, it's either 512 or 8192 though } else if (ByteSearch.contains(bytes, SRAM) || ByteSearch.contains(bytes, SRAM_F)) { info.addInfo("Save type", "SRAM"); info.addInfo("Save size", 32 * 1024, ROMInfo.FormatMode.SIZE); } else if (ByteSearch.contains(bytes, FLASH) || ByteSearch.contains(bytes, FLASH_512)) { info.addInfo("Save type", "Flash"); info.addInfo("Save size", 64 * 1024, ROMInfo.FormatMode.SIZE); } else if (ByteSearch.contains(bytes, FLASH_1024)) { info.addInfo("Save type", "Flash"); info.addInfo("Save size", 128 * 1024, ROMInfo.FormatMode.SIZE); } }
public override void addROMInfo(ROMInfo info, ROMFile file) { info.addInfo("Platform", name); WrappedInputStream f = file.stream; byte[] entryPoint = f.read(4); info.addInfo("Entry point", entryPoint, true); byte[] nintendoLogo = f.read(156); info.addInfo("Nintendo logo", nintendoLogo, true); info.addInfo("Nintendo logo valid?", isNintendoLogoEqual(nintendoLogo)); //TODO: Bits 2 and 7 of nintendoLogo[0x99] enable debugging functions when set (undefined instruction exceptions are sent //to a user handler identified using the device type) //0x9b bits 0 and 1 also have some crap in them but I don't even know string title = f.read(12, Encoding.ASCII).TrimEnd('\0'); info.addInfo("Internal name", title); string gameCode = f.read(4, Encoding.ASCII); info.addInfo("Product code", gameCode); char gameType = gameCode[0]; info.addInfo("Type", gameType, GBA_GAME_TYPES); string shortTitle = gameCode.Substring(1, 2); info.addInfo("Short title", shortTitle); char country = gameCode[3]; info.addInfo("Country", country, NintendoCommon.COUNTRIES); string makerCode = f.read(2, Encoding.ASCII); info.addInfo("Publisher", makerCode, NintendoCommon.LICENSEE_CODES); int fixedValue = f.read(); info.addInfo("Fixed value", fixedValue, ROMInfo.FormatMode.HEX, true); info.addInfo("Fixed value valid?", fixedValue == 0x96); //This indicates the required hardware, should be 0 but it's possible that //some prototype/beta/multiboot/other weird ROMs have something else int mainUnitCode = f.read(); info.addInfo("Main unit code", mainUnitCode, true); //If bit 7 is set, the debugging handler entry point is at 0x9fe2000 and not 0x9ffc000, normally this will be 0 int deviceType = f.read(); info.addInfo("Device type", deviceType, true); byte[] reserved = f.read(7); //Should be all 0 info.addInfo("Reserved", reserved, true); int version = f.read(); info.addInfo("Version", version); int checksum = f.read(); info.addInfo("Checksum", checksum, ROMInfo.FormatMode.HEX, true); int calculatedChecksum = calculateChecksum(f); info.addInfo("Calculated checksum", calculatedChecksum, ROMInfo.FormatMode.HEX, true); info.addInfo("Checksum valid?", checksum == calculatedChecksum); byte[] reserved2 = f.read(2); info.addInfo("Reserved 2", reserved2, true); byte[] restOfCart = f.read((int)f.Length); info.addInfo("Has RTC", ByteSearch.contains(restOfCart, RTC)); detectSaveType(info, restOfCart); info.addInfo("Sound driver", detectSoundDriver(info, restOfCart)); }