all repos — mgba @ d38f99e04172915dcd8a2520fd3888dc8a23a47a

mGBA Game Boy Advance Emulator

src/gba/cheats.c (view raw)

   1/* Copyright (c) 2013-2015 Jeffrey Pfau
   2 *
   3 * This Source Code Form is subject to the terms of the Mozilla Public
   4 * License, v. 2.0. If a copy of the MPL was not distributed with this
   5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   6#include "cheats.h"
   7
   8#include "gba/gba.h"
   9#include "gba/io.h"
  10#include "util/vfs.h"
  11
  12#define MAX_LINE_LENGTH 128
  13
  14const uint32_t GBA_CHEAT_DEVICE_ID = 0xABADC0DE;
  15
  16DEFINE_VECTOR(GBACheatList, struct GBACheat);
  17DEFINE_VECTOR(GBACheatSets, struct GBACheatSet*);
  18DEFINE_VECTOR(StringList, char*);
  19
  20static const uint32_t _gsa1S[4] = { 0x09F4FBBD, 0x9681884A, 0x352027E9, 0xF3DEE5A7 };
  21static const uint32_t _par3S[4] = { 0x7AA9648F, 0x7FAE6994, 0xC0EFAAD5, 0x42712C57 };
  22
  23static const uint8_t _gsa1T1[256] = {
  24	0x31, 0x1C, 0x23, 0xE5, 0x89, 0x8E, 0xA1, 0x37, 0x74, 0x6D, 0x67, 0xFC, 0x1F, 0xC0, 0xB1, 0x94,
  25	0x3B, 0x05, 0x56, 0x86, 0x00, 0x24, 0xF0, 0x17, 0x72, 0xA2, 0x3D, 0x1B, 0xE3, 0x17, 0xC5, 0x0B,
  26	0xB9, 0xE2, 0xBD, 0x58, 0x71, 0x1B, 0x2C, 0xFF, 0xE4, 0xC9, 0x4C, 0x5E, 0xC9, 0x55, 0x33, 0x45,
  27	0x7C, 0x3F, 0xB2, 0x51, 0xFE, 0x10, 0x7E, 0x75, 0x3C, 0x90, 0x8D, 0xDA, 0x94, 0x38, 0xC3, 0xE9,
  28	0x95, 0xEA, 0xCE, 0xA6, 0x06, 0xE0, 0x4F, 0x3F, 0x2A, 0xE3, 0x3A, 0xE4, 0x43, 0xBD, 0x7F, 0xDA,
  29	0x55, 0xF0, 0xEA, 0xCB, 0x2C, 0xA8, 0x47, 0x61, 0xA0, 0xEF, 0xCB, 0x13, 0x18, 0x20, 0xAF, 0x3E,
  30	0x4D, 0x9E, 0x1E, 0x77, 0x51, 0xC5, 0x51, 0x20, 0xCF, 0x21, 0xF9, 0x39, 0x94, 0xDE, 0xDD, 0x79,
  31	0x4E, 0x80, 0xC4, 0x9D, 0x94, 0xD5, 0x95, 0x01, 0x27, 0x27, 0xBD, 0x6D, 0x78, 0xB5, 0xD1, 0x31,
  32	0x6A, 0x65, 0x74, 0x74, 0x58, 0xB3, 0x7C, 0xC9, 0x5A, 0xED, 0x50, 0x03, 0xC4, 0xA2, 0x94, 0x4B,
  33	0xF0, 0x58, 0x09, 0x6F, 0x3E, 0x7D, 0xAE, 0x7D, 0x58, 0xA0, 0x2C, 0x91, 0xBB, 0xE1, 0x70, 0xEB,
  34	0x73, 0xA6, 0x9A, 0x44, 0x25, 0x90, 0x16, 0x62, 0x53, 0xAE, 0x08, 0xEB, 0xDC, 0xF0, 0xEE, 0x77,
  35	0xC2, 0xDE, 0x81, 0xE8, 0x30, 0x89, 0xDB, 0xFE, 0xBC, 0xC2, 0xDF, 0x26, 0xE9, 0x8B, 0xD6, 0x93,
  36	0xF0, 0xCB, 0x56, 0x90, 0xC0, 0x46, 0x68, 0x15, 0x43, 0xCB, 0xE9, 0x98, 0xE3, 0xAF, 0x31, 0x25,
  37	0x4D, 0x7B, 0xF3, 0xB1, 0x74, 0xE2, 0x64, 0xAC, 0xD9, 0xF6, 0xA0, 0xD5, 0x0B, 0x9B, 0x49, 0x52,
  38	0x69, 0x3B, 0x71, 0x00, 0x2F, 0xBB, 0xBA, 0x08, 0xB1, 0xAE, 0xBB, 0xB3, 0xE1, 0xC9, 0xA6, 0x7F,
  39	0x17, 0x97, 0x28, 0x72, 0x12, 0x6E, 0x91, 0xAE, 0x3A, 0xA2, 0x35, 0x46, 0x27, 0xF8, 0x12, 0x50
  40};
  41
  42static const uint8_t _gsa1T2[256] = {
  43	0xD8, 0x65, 0x04, 0xC2, 0x65, 0xD5, 0xB0, 0x0C, 0xDF, 0x9D, 0xF0, 0xC3, 0x9A, 0x17, 0xC9, 0xA6,
  44	0xE1, 0xAC, 0x0D, 0x14, 0x2F, 0x3C, 0x2C, 0x87, 0xA2, 0xBF, 0x4D, 0x5F, 0xAC, 0x2D, 0x9D, 0xE1,
  45	0x0C, 0x9C, 0xE7, 0x7F, 0xFC, 0xA8, 0x66, 0x59, 0xAC, 0x18, 0xD7, 0x05, 0xF0, 0xBF, 0xD1, 0x8B,
  46	0x35, 0x9F, 0x59, 0xB4, 0xBA, 0x55, 0xB2, 0x85, 0xFD, 0xB1, 0x72, 0x06, 0x73, 0xA4, 0xDB, 0x48,
  47	0x7B, 0x5F, 0x67, 0xA5, 0x95, 0xB9, 0xA5, 0x4A, 0xCF, 0xD1, 0x44, 0xF3, 0x81, 0xF5, 0x6D, 0xF6,
  48	0x3A, 0xC3, 0x57, 0x83, 0xFA, 0x8E, 0x15, 0x2A, 0xA2, 0x04, 0xB2, 0x9D, 0xA8, 0x0D, 0x7F, 0xB8,
  49	0x0F, 0xF6, 0xAC, 0xBE, 0x97, 0xCE, 0x16, 0xE6, 0x31, 0x10, 0x60, 0x16, 0xB5, 0x83, 0x45, 0xEE,
  50	0xD7, 0x5F, 0x2C, 0x08, 0x58, 0xB1, 0xFD, 0x7E, 0x79, 0x00, 0x34, 0xAD, 0xB5, 0x31, 0x34, 0x39,
  51	0xAF, 0xA8, 0xDD, 0x52, 0x6A, 0xB0, 0x60, 0x35, 0xB8, 0x1D, 0x52, 0xF5, 0xF5, 0x30, 0x00, 0x7B,
  52	0xF4, 0xBA, 0x03, 0xCB, 0x3A, 0x84, 0x14, 0x8A, 0x6A, 0xEF, 0x21, 0xBD, 0x01, 0xD8, 0xA0, 0xD4,
  53	0x43, 0xBE, 0x23, 0xE7, 0x76, 0x27, 0x2C, 0x3F, 0x4D, 0x3F, 0x43, 0x18, 0xA7, 0xC3, 0x47, 0xA5,
  54	0x7A, 0x1D, 0x02, 0x55, 0x09, 0xD1, 0xFF, 0x55, 0x5E, 0x17, 0xA0, 0x56, 0xF4, 0xC9, 0x6B, 0x90,
  55	0xB4, 0x80, 0xA5, 0x07, 0x22, 0xFB, 0x22, 0x0D, 0xD9, 0xC0, 0x5B, 0x08, 0x35, 0x05, 0xC1, 0x75,
  56	0x4F, 0xD0, 0x51, 0x2D, 0x2E, 0x5E, 0x69, 0xE7, 0x3B, 0xC2, 0xDA, 0xFF, 0xF6, 0xCE, 0x3E, 0x76,
  57	0xE8, 0x36, 0x8C, 0x39, 0xD8, 0xF3, 0xE9, 0xA6, 0x42, 0xE6, 0xC1, 0x4C, 0x05, 0xBE, 0x17, 0xF2,
  58	0x5C, 0x1B, 0x19, 0xDB, 0x0F, 0xF3, 0xF8, 0x49, 0xEB, 0x36, 0xF6, 0x40, 0x6F, 0xAD, 0xC1, 0x8C
  59};
  60
  61static const uint8_t _par3T1[256] = {
  62	0xD0, 0xFF, 0xBA, 0xE5, 0xC1, 0xC7, 0xDB, 0x5B, 0x16, 0xE3, 0x6E, 0x26, 0x62, 0x31, 0x2E, 0x2A,
  63	0xD1, 0xBB, 0x4A, 0xE6, 0xAE, 0x2F, 0x0A, 0x90, 0x29, 0x90, 0xB6, 0x67, 0x58, 0x2A, 0xB4, 0x45,
  64	0x7B, 0xCB, 0xF0, 0x73, 0x84, 0x30, 0x81, 0xC2, 0xD7, 0xBE, 0x89, 0xD7, 0x4E, 0x73, 0x5C, 0xC7,
  65	0x80, 0x1B, 0xE5, 0xE4, 0x43, 0xC7, 0x46, 0xD6, 0x6F, 0x7B, 0xBF, 0xED, 0xE5, 0x27, 0xD1, 0xB5,
  66	0xD0, 0xD8, 0xA3, 0xCB, 0x2B, 0x30, 0xA4, 0xF0, 0x84, 0x14, 0x72, 0x5C, 0xFF, 0xA4, 0xFB, 0x54,
  67	0x9D, 0x70, 0xE2, 0xFF, 0xBE, 0xE8, 0x24, 0x76, 0xE5, 0x15, 0xFB, 0x1A, 0xBC, 0x87, 0x02, 0x2A,
  68	0x58, 0x8F, 0x9A, 0x95, 0xBD, 0xAE, 0x8D, 0x0C, 0xA5, 0x4C, 0xF2, 0x5C, 0x7D, 0xAD, 0x51, 0xFB,
  69	0xB1, 0x22, 0x07, 0xE0, 0x29, 0x7C, 0xEB, 0x98, 0x14, 0xC6, 0x31, 0x97, 0xE4, 0x34, 0x8F, 0xCC,
  70	0x99, 0x56, 0x9F, 0x78, 0x43, 0x91, 0x85, 0x3F, 0xC2, 0xD0, 0xD1, 0x80, 0xD1, 0x77, 0xA7, 0xE2,
  71	0x43, 0x99, 0x1D, 0x2F, 0x8B, 0x6A, 0xE4, 0x66, 0x82, 0xF7, 0x2B, 0x0B, 0x65, 0x14, 0xC0, 0xC2,
  72	0x1D, 0x96, 0x78, 0x1C, 0xC4, 0xC3, 0xD2, 0xB1, 0x64, 0x07, 0xD7, 0x6F, 0x02, 0xE9, 0x44, 0x31,
  73	0xDB, 0x3C, 0xEB, 0x93, 0xED, 0x9A, 0x57, 0x05, 0xB9, 0x0E, 0xAF, 0x1F, 0x48, 0x11, 0xDC, 0x35,
  74	0x6C, 0xB8, 0xEE, 0x2A, 0x48, 0x2B, 0xBC, 0x89, 0x12, 0x59, 0xCB, 0xD1, 0x18, 0xEA, 0x72, 0x11,
  75	0x01, 0x75, 0x3B, 0xB5, 0x56, 0xF4, 0x8B, 0xA0, 0x41, 0x75, 0x86, 0x7B, 0x94, 0x12, 0x2D, 0x4C,
  76	0x0C, 0x22, 0xC9, 0x4A, 0xD8, 0xB1, 0x8D, 0xF0, 0x55, 0x2E, 0x77, 0x50, 0x1C, 0x64, 0x77, 0xAA,
  77	0x3E, 0xAC, 0xD3, 0x3D, 0xCE, 0x60, 0xCA, 0x5D, 0xA0, 0x92, 0x78, 0xC6, 0x51, 0xFE, 0xF9, 0x30
  78};
  79
  80static const uint8_t _par3T2[256] = {
  81	0xAA, 0xAF, 0xF0, 0x72, 0x90, 0xF7, 0x71, 0x27, 0x06, 0x11, 0xEB, 0x9C, 0x37, 0x12, 0x72, 0xAA,
  82	0x65, 0xBC, 0x0D, 0x4A, 0x76, 0xF6, 0x5C, 0xAA, 0xB0, 0x7A, 0x7D, 0x81, 0xC1, 0xCE, 0x2F, 0x9F,
  83	0x02, 0x75, 0x38, 0xC8, 0xFC, 0x66, 0x05, 0xC2, 0x2C, 0xBD, 0x91, 0xAD, 0x03, 0xB1, 0x88, 0x93,
  84	0x31, 0xC6, 0xAB, 0x40, 0x23, 0x43, 0x76, 0x54, 0xCA, 0xE7, 0x00, 0x96, 0x9F, 0xD8, 0x24, 0x8B,
  85	0xE4, 0xDC, 0xDE, 0x48, 0x2C, 0xCB, 0xF7, 0x84, 0x1D, 0x45, 0xE5, 0xF1, 0x75, 0xA0, 0xED, 0xCD,
  86	0x4B, 0x24, 0x8A, 0xB3, 0x98, 0x7B, 0x12, 0xB8, 0xF5, 0x63, 0x97, 0xB3, 0xA6, 0xA6, 0x0B, 0xDC,
  87	0xD8, 0x4C, 0xA8, 0x99, 0x27, 0x0F, 0x8F, 0x94, 0x63, 0x0F, 0xB0, 0x11, 0x94, 0xC7, 0xE9, 0x7F,
  88	0x3B, 0x40, 0x72, 0x4C, 0xDB, 0x84, 0x78, 0xFE, 0xB8, 0x56, 0x08, 0x80, 0xDF, 0x20, 0x2F, 0xB9,
  89	0x66, 0x2D, 0x60, 0x63, 0xF5, 0x18, 0x15, 0x1B, 0x86, 0x85, 0xB9, 0xB4, 0x68, 0x0E, 0xC6, 0xD1,
  90	0x8A, 0x81, 0x2B, 0xB3, 0xF6, 0x48, 0xF0, 0x4F, 0x9C, 0x28, 0x1C, 0xA4, 0x51, 0x2F, 0xD7, 0x4B,
  91	0x17, 0xE7, 0xCC, 0x50, 0x9F, 0xD0, 0xD1, 0x40, 0x0C, 0x0D, 0xCA, 0x83, 0xFA, 0x5E, 0xCA, 0xEC,
  92	0xBF, 0x4E, 0x7C, 0x8F, 0xF0, 0xAE, 0xC2, 0xD3, 0x28, 0x41, 0x9B, 0xC8, 0x04, 0xB9, 0x4A, 0xBA,
  93	0x72, 0xE2, 0xB5, 0x06, 0x2C, 0x1E, 0x0B, 0x2C, 0x7F, 0x11, 0xA9, 0x26, 0x51, 0x9D, 0x3F, 0xF8,
  94	0x62, 0x11, 0x2E, 0x89, 0xD2, 0x9D, 0x35, 0xB1, 0xE4, 0x0A, 0x4D, 0x93, 0x01, 0xA7, 0xD1, 0x2D,
  95	0x00, 0x87, 0xE2, 0x2D, 0xA4, 0xE9, 0x0A, 0x06, 0x66, 0xF8, 0x1F, 0x44, 0x75, 0xB5, 0x6B, 0x1C,
  96	0xFC, 0x31, 0x09, 0x48, 0xA3, 0xFF, 0x92, 0x12, 0x58, 0xE9, 0xFA, 0xAE, 0x4F, 0xE2, 0xB4, 0xCC
  97};
  98
  99static int32_t _readMem(struct ARMCore* cpu, uint32_t address, int width) {
 100	switch (width) {
 101	case 1:
 102		return cpu->memory.load8(cpu, address, 0);
 103	case 2:
 104		return cpu->memory.load16(cpu, address, 0);
 105	case 4:
 106		return cpu->memory.load32(cpu, address, 0);
 107	}
 108	return 0;
 109}
 110
 111static void _writeMem(struct ARMCore* cpu, uint32_t address, int width, int32_t value) {
 112	switch (width) {
 113	case 1:
 114		cpu->memory.store8(cpu, address, value, 0);
 115		break;
 116	case 2:
 117		cpu->memory.store16(cpu, address, value, 0);
 118		break;
 119	case 4:
 120		cpu->memory.store32(cpu, address, value, 0);
 121		break;
 122	}
 123}
 124
 125static int _hexDigit(char digit) {
 126	switch (digit) {
 127	case '0':
 128	case '1':
 129	case '2':
 130	case '3':
 131	case '4':
 132	case '5':
 133	case '6':
 134	case '7':
 135	case '8':
 136	case '9':
 137		return digit - '0';
 138
 139	case 'a':
 140	case 'b':
 141	case 'c':
 142	case 'd':
 143	case 'e':
 144	case 'f':
 145		return digit - 'a' + 10;
 146
 147	case 'A':
 148	case 'B':
 149	case 'C':
 150	case 'D':
 151	case 'E':
 152	case 'F':
 153		return digit - 'A' + 10;
 154
 155	default:
 156		return -1;
 157	}
 158}
 159
 160static const char* _hex32(const char* line, uint32_t* out) {
 161	uint32_t value = 0;
 162	int i;
 163	for (i = 0; i < 8; ++i, ++line) {
 164		char digit = *line;
 165		value <<= 4;
 166		int nybble = _hexDigit(digit);
 167		if (nybble < 0) {
 168			return 0;
 169		}
 170		value |= nybble;
 171	}
 172	*out = value;
 173	return line;
 174}
 175
 176static const char* _hex16(const char* line, uint16_t* out) {
 177	uint16_t value = 0;
 178	*out = 0;
 179	int i;
 180	for (i = 0; i < 4; ++i, ++line) {
 181		char digit = *line;
 182		value <<= 4;
 183		int nybble = _hexDigit(digit);
 184		if (nybble < 0) {
 185			return 0;
 186		}
 187		value |= nybble;
 188	}
 189	*out = value;
 190	return line;
 191}
 192
 193static void _registerLine(struct GBACheatSet* cheats, const char* line) {
 194	*StringListAppend(&cheats->lines) = strdup(line);
 195}
 196
 197// http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
 198static void _decryptGameShark(uint32_t* op1, uint32_t* op2, const uint32_t* seeds) {
 199	uint32_t sum = 0xC6EF3720;
 200	int i;
 201	for (i = 0; i < 32; ++i) {
 202		*op2 -= ((*op1 << 4) + seeds[2]) ^ (*op1 + sum) ^ ((*op1 >> 5) + seeds[3]);
 203		*op1 -= ((*op2 << 4) + seeds[0]) ^ (*op2 + sum) ^ ((*op2 >> 5) + seeds[1]);
 204		sum -= 0x9E3779B9;
 205	}
 206}
 207
 208static void _reseedGameShark(uint32_t* seeds, uint16_t params, const uint8_t* t1, const uint8_t* t2) {
 209	int x, y;
 210	int s0 = params >> 8;
 211	int s1 = params & 0xFF;
 212	for (y = 0; y < 4; ++y) {
 213		for (x = 0; x < 4; ++x) {
 214			uint8_t z = t1[(s0 + x) & 0xFF] + t2[(s1 + y) & 0xFF];
 215			seeds[y] <<= 8;
 216			seeds[y] |= z;
 217		}
 218	}
 219}
 220
 221static void _setGameSharkVersion(struct GBACheatSet* cheats, int version) {
 222	cheats->gsaVersion = 1;
 223	switch (version) {
 224	case 1:
 225		memcpy(cheats->gsaSeeds, _gsa1S, 4 * sizeof(uint32_t));
 226		break;
 227	case 3:
 228		memcpy(cheats->gsaSeeds, _par3S, 4 * sizeof(uint32_t));
 229		break;
 230	}
 231}
 232
 233static bool _addGSA1(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) {
 234	enum GBAGameSharkType type = op1 >> 28;
 235	struct GBACheat* cheat = 0;
 236
 237	if (cheats->incompleteCheat) {
 238		if (cheats->remainingAddresses > 0) {
 239			cheat = GBACheatListAppend(&cheats->list);
 240			cheat->type = CHEAT_ASSIGN;
 241			cheat->width = 4;
 242			cheat->address = op1;
 243			cheat->operand = cheats->incompleteCheat->operand;
 244			cheat->repeat = 1;
 245			--cheats->remainingAddresses;
 246		}
 247		if (cheats->remainingAddresses > 0) {
 248			cheat = GBACheatListAppend(&cheats->list);
 249			cheat->type = CHEAT_ASSIGN;
 250			cheat->width = 4;
 251			cheat->address = op2;
 252			cheat->operand = cheats->incompleteCheat->operand;
 253			cheat->repeat = 1;
 254			--cheats->remainingAddresses;
 255		}
 256		if (cheats->remainingAddresses == 0) {
 257			cheats->incompleteCheat = 0;
 258		}
 259		return true;
 260	}
 261
 262	switch (type) {
 263	case GSA_ASSIGN_1:
 264		cheat = GBACheatListAppend(&cheats->list);
 265		cheat->type = CHEAT_ASSIGN;
 266		cheat->width = 1;
 267		cheat->address = op1 & 0x0FFFFFFF;
 268		break;
 269	case GSA_ASSIGN_2:
 270		cheat = GBACheatListAppend(&cheats->list);
 271		cheat->type = CHEAT_ASSIGN;
 272		cheat->width = 2;
 273		cheat->address = op1 & 0x0FFFFFFF;
 274		break;
 275	case GSA_ASSIGN_4:
 276		cheat = GBACheatListAppend(&cheats->list);
 277		cheat->type = CHEAT_ASSIGN;
 278		cheat->width = 4;
 279		cheat->address = op1 & 0x0FFFFFFF;
 280		break;
 281	case GSA_ASSIGN_LIST:
 282		cheats->remainingAddresses = (op1 & 0xFFFF) - 1;
 283		cheat = GBACheatListAppend(&cheats->list);
 284		cheat->type = CHEAT_ASSIGN;
 285		cheat->width = 4;
 286		cheat->address = op2;
 287		cheats->incompleteCheat = cheat;
 288		break;
 289	case GSA_PATCH:
 290		cheats->romPatches[0].address = (op1 & 0xFFFFFF) << 1;
 291		cheats->romPatches[0].newValue = op2;
 292		cheats->romPatches[0].applied = false;
 293		cheats->romPatches[0].exists = true;
 294		return true;
 295	case GSA_BUTTON:
 296		// TODO: Implement button
 297		GBALog(0, GBA_LOG_STUB, "GameShark button unimplemented");
 298		return false;
 299	case GSA_IF_EQ:
 300		if (op1 == 0xDEADFACE) {
 301			_reseedGameShark(cheats->gsaSeeds, op2, _gsa1T1, _gsa1T2);
 302			return true;
 303		}
 304		cheat = GBACheatListAppend(&cheats->list);
 305		cheat->type = CHEAT_IF_EQ;
 306		cheat->width = 2;
 307		cheat->address = op1 & 0x0FFFFFFF;
 308		break;
 309	case GSA_IF_EQ_RANGE:
 310		cheat = GBACheatListAppend(&cheats->list);
 311		cheat->type = CHEAT_IF_EQ;
 312		cheat->width = 2;
 313		cheat->address = op2 & 0x0FFFFFFF;
 314		cheat->operand = op1 & 0xFFFF;
 315		cheat->repeat = (op1 >> 16) & 0xFF;
 316		return true;
 317	case GSA_HOOK:
 318		if (cheats->hook) {
 319			return false;
 320		}
 321		cheats->hook = malloc(sizeof(*cheats->hook));
 322		cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
 323		cheats->hook->mode = MODE_THUMB;
 324		cheats->hook->refs = 1;
 325		cheats->hook->reentries = 0;
 326		return true;
 327	default:
 328		return false;
 329	}
 330	cheat->operand = op2;
 331	cheat->repeat = 1;
 332	return true;
 333}
 334
 335static uint32_t _parAddr(uint32_t x) {
 336	return (x & 0xFFFFF) | ((x << 4) & 0x0F000000);
 337}
 338
 339static void _parEndBlock(struct GBACheatSet* cheats) {
 340	size_t size = GBACheatListSize(&cheats->list) - GBACheatListIndex(&cheats->list, cheats->currentBlock);
 341	if (cheats->currentBlock->repeat) {
 342		cheats->currentBlock->negativeRepeat = size - cheats->currentBlock->repeat;
 343	} else {
 344		cheats->currentBlock->repeat = size;
 345	}
 346	cheats->currentBlock = 0;
 347}
 348
 349static void _parElseBlock(struct GBACheatSet* cheats) {
 350	size_t size = GBACheatListSize(&cheats->list) - GBACheatListIndex(&cheats->list, cheats->currentBlock);
 351	cheats->currentBlock->repeat = size;
 352}
 353
 354static bool _addPAR3Cond(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) {
 355	enum GBAActionReplay3Condition condition = op1 & PAR3_COND;
 356	int width = 1 << ((op1 & PAR3_WIDTH) >> PAR3_WIDTH_BASE);
 357	if (width > 4) {
 358		// TODO: Always false conditions
 359		return false;
 360	}
 361	if ((op1 & PAR3_ACTION) == PAR3_ACTION_DISABLE) {
 362		// TODO: Codes that disable
 363		return false;
 364	}
 365
 366	struct GBACheat* cheat = GBACheatListAppend(&cheats->list);
 367	cheat->address = _parAddr(op1);
 368	cheat->width = width;
 369	cheat->operand = op2 & (0xFFFFFFFFU >> ((4 - width) * 8));
 370	cheat->addressOffset = 0;
 371	cheat->operandOffset = 0;
 372
 373	switch (op1 & PAR3_ACTION) {
 374	case PAR3_ACTION_NEXT:
 375		cheat->repeat = 1;
 376		cheat->negativeRepeat = 0;
 377		break;
 378	case PAR3_ACTION_NEXT_TWO:
 379		cheat->repeat = 2;
 380		cheat->negativeRepeat = 0;
 381		break;
 382	case PAR3_ACTION_BLOCK:
 383		cheat->repeat = 0;
 384		cheat->negativeRepeat = 0;
 385		if (cheats->currentBlock) {
 386			_parEndBlock(cheats);
 387		}
 388		cheats->currentBlock = cheat;
 389		break;
 390	}
 391
 392	switch (condition) {
 393	case PAR3_COND_OTHER:
 394		// We shouldn't be able to get here
 395		GBALog(0, GBA_LOG_ERROR, "Unexpectedly created 'other' PARv3 code");
 396		cheat->type = CHEAT_IF_LAND;
 397		cheat->operand = 0;
 398		break;
 399	case PAR3_COND_EQ:
 400		cheat->type = CHEAT_IF_EQ;
 401		break;
 402	case PAR3_COND_NE:
 403		cheat->type = CHEAT_IF_NE;
 404		break;
 405	case PAR3_COND_LT:
 406		cheat->type = CHEAT_IF_LT;
 407		break;
 408	case PAR3_COND_GT:
 409		cheat->type = CHEAT_IF_GT;
 410		break;
 411	case PAR3_COND_ULT:
 412		cheat->type = CHEAT_IF_ULT;
 413		break;
 414	case PAR3_COND_UGT:
 415		cheat->type = CHEAT_IF_UGT;
 416		break;
 417	case PAR3_COND_LAND:
 418		cheat->type = CHEAT_IF_LAND;
 419		break;
 420	}
 421	return true;
 422}
 423
 424static bool _addPAR3Special(struct GBACheatSet* cheats, uint32_t op2) {
 425	struct GBACheat* cheat;
 426	switch (op2 & 0xFF000000) {
 427	case PAR3_OTHER_SLOWDOWN:
 428		// TODO: Slowdown
 429		return false;
 430	case PAR3_OTHER_BUTTON_1:
 431	case PAR3_OTHER_BUTTON_2:
 432	case PAR3_OTHER_BUTTON_4:
 433		// TODO: Button
 434		GBALog(0, GBA_LOG_STUB, "GameShark button unimplemented");
 435		return false;
 436	// TODO: Fix overriding existing patches
 437	case PAR3_OTHER_PATCH_1:
 438		cheats->romPatches[0].address = (op2 & 0xFFFFFF) << 1;
 439		cheats->romPatches[0].applied = false;
 440		cheats->romPatches[0].exists = true;
 441		cheats->incompletePatch = &cheats->romPatches[0];
 442		break;
 443	case PAR3_OTHER_PATCH_2:
 444		cheats->romPatches[1].address = (op2 & 0xFFFFFF) << 1;
 445		cheats->romPatches[1].applied = false;
 446		cheats->romPatches[1].exists = true;
 447		cheats->incompletePatch = &cheats->romPatches[1];
 448		break;
 449	case PAR3_OTHER_PATCH_3:
 450		cheats->romPatches[2].address = (op2 & 0xFFFFFF) << 1;
 451		cheats->romPatches[2].applied = false;
 452		cheats->romPatches[2].exists = true;
 453		cheats->incompletePatch = &cheats->romPatches[2];
 454		break;
 455	case PAR3_OTHER_PATCH_4:
 456		cheats->romPatches[3].address = (op2 & 0xFFFFFF) << 1;
 457		cheats->romPatches[3].applied = false;
 458		cheats->romPatches[3].exists = true;
 459		cheats->incompletePatch = &cheats->romPatches[3];
 460		break;
 461	case PAR3_OTHER_ENDIF:
 462		if (cheats->currentBlock) {
 463			_parEndBlock(cheats);
 464			return true;
 465		}
 466		return false;
 467	case PAR3_OTHER_ELSE:
 468		if (cheats->currentBlock) {
 469			_parElseBlock(cheats);
 470			return true;
 471		}
 472		return false;
 473	case PAR3_OTHER_FILL_1:
 474		cheat = GBACheatListAppend(&cheats->list);
 475		cheat->address = _parAddr(op2);
 476		cheat->width = 1;
 477		cheats->incompleteCheat = cheat;
 478		break;
 479	case PAR3_OTHER_FILL_2:
 480		cheat = GBACheatListAppend(&cheats->list);
 481		cheat->address = _parAddr(op2);
 482		cheat->width = 2;
 483		cheats->incompleteCheat = cheat;
 484		break;
 485	case PAR3_OTHER_FILL_4:
 486		cheat = GBACheatListAppend(&cheats->list);
 487		cheat->address = _parAddr(op2);
 488		cheat->width = 3;
 489		cheats->incompleteCheat = cheat;
 490		break;
 491	}
 492	return true;
 493}
 494
 495static bool _addPAR3(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) {
 496	if (cheats->incompletePatch) {
 497		cheats->incompletePatch->newValue = op1;
 498		cheats->incompletePatch = 0;
 499		return true;
 500	}
 501	if (cheats->incompleteCheat) {
 502		cheats->incompleteCheat->operand = op1 & (0xFFFFFFFFU >> ((4 - cheats->incompleteCheat->width) * 8));
 503		cheats->incompleteCheat->addressOffset = op2 >> 24;
 504		cheats->incompleteCheat->repeat = (op2 >> 16) & 0xFF;
 505		cheats->incompleteCheat->addressOffset = (op2 & 0xFFFF) * cheats->incompleteCheat->width;
 506		cheats->incompleteCheat = 0;
 507		return true;
 508	}
 509
 510	if (op2 == 0x001DC0DE) {
 511		return true;
 512	}
 513
 514	switch (op1) {
 515	case 0x00000000:
 516		return _addPAR3Special(cheats, op2);
 517	case 0xDEADFACE:
 518		_reseedGameShark(cheats->gsaSeeds, op2, _par3T1, _par3T2);
 519		return true;
 520	}
 521
 522	if (op1 >> 24 == 0xC4) {
 523		if (cheats->hook) {
 524			return false;
 525		}
 526		cheats->hook = malloc(sizeof(*cheats->hook));
 527		cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
 528		cheats->hook->mode = MODE_THUMB;
 529		cheats->hook->refs = 1;
 530		cheats->hook->reentries = 0;
 531		return true;
 532	}
 533
 534	if (op1 & PAR3_COND) {
 535		return _addPAR3Cond(cheats, op1, op2);
 536	}
 537
 538	int width = 1 << ((op1 & PAR3_WIDTH) >> PAR3_WIDTH_BASE);
 539	struct GBACheat* cheat = GBACheatListAppend(&cheats->list);
 540	cheat->address = _parAddr(op1);
 541	cheat->operandOffset = 0;
 542	cheat->addressOffset = 0;
 543	cheat->repeat = 1;
 544
 545	switch (op1 & PAR3_BASE) {
 546	case PAR3_BASE_ASSIGN:
 547		cheat->type = CHEAT_ASSIGN;
 548		cheat->addressOffset = width;
 549		if (width < 4) {
 550			cheat->repeat = (op2 >> (width * 8)) + 1;
 551		}
 552		break;
 553	case PAR3_BASE_INDIRECT:
 554		cheat->type = CHEAT_ASSIGN_INDIRECT;
 555		if (width < 4) {
 556			cheat->addressOffset = (op2 >> (width * 8)) * width;
 557		}
 558		break;
 559	case PAR3_BASE_ADD:
 560		cheat->type = CHEAT_ADD;
 561		break;
 562	case PAR3_BASE_OTHER:
 563		width = ((op1 >> 24) & 1) + 1;
 564		cheat->type = CHEAT_ASSIGN;
 565		cheat->address = BASE_IO | (op1 & OFFSET_MASK);
 566		break;
 567	}
 568
 569	cheat->width = width;
 570	cheat->operand = op2 & (0xFFFFFFFFU >> ((4 - width) * 8));
 571	return true;
 572}
 573
 574static void _addBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
 575	if (!device->p || !cheats->hook) {
 576		return;
 577	}
 578	++cheats->hook->reentries;
 579	if (cheats->hook->reentries > 1) {
 580		return;
 581	}
 582	GBASetBreakpoint(device->p, &device->d, cheats->hook->address, cheats->hook->mode, &cheats->hook->patchedOpcode);
 583}
 584
 585static void _removeBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
 586	if (!device->p || !cheats->hook) {
 587		return;
 588	}
 589	--cheats->hook->reentries;
 590	if (cheats->hook->reentries > 0) {
 591		return;
 592	}
 593	GBAClearBreakpoint(device->p, cheats->hook->address, cheats->hook->mode, cheats->hook->patchedOpcode);
 594}
 595
 596static void _patchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
 597	if (!device->p) {
 598		return;
 599	}
 600	int i;
 601	for (i = 0; i < MAX_ROM_PATCHES; ++i) {
 602		if (!cheats->romPatches[i].exists || cheats->romPatches[i].applied) {
 603			continue;
 604		}
 605		GBAPatch16(device->p->cpu, cheats->romPatches[i].address, cheats->romPatches[i].newValue, &cheats->romPatches[i].oldValue);
 606		cheats->romPatches[i].applied = true;
 607	}
 608}
 609
 610static void _unpatchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
 611	if (!device->p) {
 612		return;
 613	}
 614	int i;
 615	for (i = 0; i < MAX_ROM_PATCHES; ++i) {
 616		if (!cheats->romPatches[i].exists || !cheats->romPatches[i].applied) {
 617			continue;
 618		}
 619		GBAPatch16(device->p->cpu, cheats->romPatches[i].address, cheats->romPatches[i].oldValue, 0);
 620		cheats->romPatches[i].applied = false;
 621	}
 622}
 623
 624static void GBACheatDeviceInit(struct ARMCore*, struct ARMComponent*);
 625static void GBACheatDeviceDeinit(struct ARMComponent*);
 626
 627void GBACheatDeviceCreate(struct GBACheatDevice* device) {
 628	device->d.id = GBA_CHEAT_DEVICE_ID;
 629	device->d.init = GBACheatDeviceInit;
 630	device->d.deinit = GBACheatDeviceDeinit;
 631	GBACheatSetsInit(&device->cheats, 4);
 632}
 633
 634void GBACheatDeviceDestroy(struct GBACheatDevice* device) {
 635	size_t i;
 636	for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
 637		struct GBACheatSet* set = *GBACheatSetsGetPointer(&device->cheats, i);
 638		GBACheatSetDeinit(set);
 639		free(set);
 640	}
 641	GBACheatSetsDeinit(&device->cheats);
 642}
 643
 644void GBACheatSetInit(struct GBACheatSet* set, const char* name) {
 645	GBACheatListInit(&set->list, 4);
 646	StringListInit(&set->lines, 4);
 647	set->incompleteCheat = 0;
 648	set->incompletePatch = 0;
 649	set->currentBlock = 0;
 650	set->gsaVersion = 0;
 651	set->remainingAddresses = 0;
 652	set->hook = 0;
 653	int i;
 654	for (i = 0; i < MAX_ROM_PATCHES; ++i) {
 655		set->romPatches[i].exists = false;
 656	}
 657	if (name) {
 658		set->name = strdup(name);
 659	} else {
 660		set->name = 0;
 661	}
 662	set->enabled = true;
 663}
 664
 665void GBACheatSetDeinit(struct GBACheatSet* set) {
 666	GBACheatListDeinit(&set->list);
 667	size_t i;
 668	for (i = 0; i < StringListSize(&set->lines); ++i) {
 669		free(*StringListGetPointer(&set->lines, i));
 670	}
 671	if (set->name) {
 672		free(set->name);
 673	}
 674	if (set->hook) {
 675		--set->hook->refs;
 676		if (set->hook->refs == 0) {
 677			free(set->hook);
 678		}
 679	}
 680}
 681
 682void GBACheatAttachDevice(struct GBA* gba, struct GBACheatDevice* device) {
 683	if (gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) {
 684		ARMHotplugDetach(gba->cpu, GBA_COMPONENT_CHEAT_DEVICE);
 685	}
 686	gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE] = &device->d;
 687	ARMHotplugAttach(gba->cpu, GBA_COMPONENT_CHEAT_DEVICE);
 688}
 689
 690void GBACheatAddSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
 691	*GBACheatSetsAppend(&device->cheats) = cheats;
 692	_addBreakpoint(device, cheats);
 693	_patchROM(device, cheats);
 694}
 695
 696void GBACheatRemoveSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
 697	size_t i;
 698	for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
 699		if (*GBACheatSetsGetPointer(&device->cheats, i) == cheats) {
 700			break;
 701		}
 702	}
 703	if (i == GBACheatSetsSize(&device->cheats)) {
 704		return;
 705	}
 706	GBACheatSetsShift(&device->cheats, i, 1);
 707	_unpatchROM(device, cheats);
 708	_removeBreakpoint(device, cheats);
 709}
 710
 711bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t op2) {
 712	char line[14] = "XXXXXXXX XXXX";
 713	snprintf(line, sizeof(line), "%08X %04X", op1, op2);
 714	_registerLine(cheats, line);
 715
 716	enum GBACodeBreakerType type = op1 >> 28;
 717	struct GBACheat* cheat = 0;
 718
 719	if (cheats->incompleteCheat) {
 720		cheats->incompleteCheat->repeat = op1 & 0xFFFF;
 721		cheats->incompleteCheat->addressOffset = op2;
 722		cheats->incompleteCheat->operandOffset = 0;
 723		cheats->incompleteCheat = 0;
 724		return true;
 725	}
 726
 727	switch (type) {
 728	case CB_GAME_ID:
 729		// TODO: Run checksum
 730		return true;
 731	case CB_HOOK:
 732		if (cheats->hook) {
 733			return false;
 734		}
 735		cheats->hook = malloc(sizeof(*cheats->hook));
 736		cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
 737		cheats->hook->mode = MODE_THUMB;
 738		cheats->hook->refs = 1;
 739		cheats->hook->reentries = 0;
 740		return true;
 741	case CB_OR_2:
 742		cheat = GBACheatListAppend(&cheats->list);
 743		cheat->type = CHEAT_OR;
 744		cheat->width = 2;
 745		break;
 746	case CB_ASSIGN_1:
 747		cheat = GBACheatListAppend(&cheats->list);
 748		cheat->type = CHEAT_ASSIGN;
 749		cheat->width = 1;
 750		break;
 751	case CB_FILL:
 752		cheat = GBACheatListAppend(&cheats->list);
 753		cheat->type = CHEAT_ASSIGN;
 754		cheat->width = 2;
 755		cheats->incompleteCheat = cheat;
 756		break;
 757	case CB_FILL_8:
 758		GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2);
 759		return false;
 760	case CB_AND_2:
 761		cheat = GBACheatListAppend(&cheats->list);
 762		cheat->type = CHEAT_AND;
 763		cheat->width = 2;
 764		break;
 765	case CB_IF_EQ:
 766		cheat = GBACheatListAppend(&cheats->list);
 767		cheat->type = CHEAT_IF_EQ;
 768		cheat->width = 2;
 769		break;
 770	case CB_ASSIGN_2:
 771		cheat = GBACheatListAppend(&cheats->list);
 772		cheat->type = CHEAT_ASSIGN;
 773		cheat->width = 2;
 774		break;
 775	case CB_ENCRYPT:
 776		GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker encryption not supported");
 777		return false;
 778	case CB_IF_NE:
 779		cheat = GBACheatListAppend(&cheats->list);
 780		cheat->type = CHEAT_IF_NE;
 781		cheat->width = 2;
 782		break;
 783	case CB_IF_GT:
 784		cheat = GBACheatListAppend(&cheats->list);
 785		cheat->type = CHEAT_IF_GT;
 786		cheat->width = 2;
 787		break;
 788	case CB_IF_LT:
 789		cheat = GBACheatListAppend(&cheats->list);
 790		cheat->type = CHEAT_IF_LT;
 791		cheat->width = 2;
 792		break;
 793	case CB_IF_SPECIAL:
 794		switch (op1 & 0x0FFFFFFF) {
 795		case 0x20:
 796			cheat = GBACheatListAppend(&cheats->list);
 797			cheat->type = CHEAT_IF_AND;
 798			cheat->width = 2;
 799			cheat->address = BASE_IO | REG_JOYSTAT;
 800			cheat->operand = op2;
 801			cheat->repeat = 1;
 802			return true;
 803		default:
 804			GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2);
 805			return false;
 806		}
 807	case CB_ADD_2:
 808		cheat = GBACheatListAppend(&cheats->list);
 809		cheat->type = CHEAT_ADD;
 810		cheat->width = 2;
 811		break;
 812	case CB_IF_AND:
 813		cheat = GBACheatListAppend(&cheats->list);
 814		cheat->type = CHEAT_IF_AND;
 815		cheat->width = 2;
 816		break;
 817	}
 818
 819	cheat->address = op1 & 0x0FFFFFFF;
 820	cheat->operand = op2;
 821	cheat->repeat = 1;
 822	cheat->negativeRepeat = 0;
 823	return true;
 824}
 825
 826bool GBACheatAddCodeBreakerLine(struct GBACheatSet* cheats, const char* line) {
 827	uint32_t op1;
 828	uint16_t op2;
 829	line = _hex32(line, &op1);
 830	if (!line) {
 831		return false;
 832	}
 833	while (*line == ' ') {
 834		++line;
 835	}
 836	line = _hex16(line, &op2);
 837	if (!line) {
 838		return false;
 839	}
 840	return GBACheatAddCodeBreaker(cheats, op1, op2);
 841}
 842
 843bool GBACheatAddGameShark(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
 844	uint32_t o1 = op1;
 845	uint32_t o2 = op2;
 846	char line[18] = "XXXXXXXX XXXXXXXX";
 847	snprintf(line, sizeof(line), "%08X %08X", op1, op2);
 848	_registerLine(set, line);
 849
 850	switch (set->gsaVersion) {
 851	case 0:
 852		_setGameSharkVersion(set, 1);
 853		// Fall through
 854	case 1:
 855		_decryptGameShark(&o1, &o2, set->gsaSeeds);
 856		return _addGSA1(set, o1, o2);
 857	}
 858	return false;
 859}
 860
 861bool GBACheatAddGameSharkLine(struct GBACheatSet* cheats, const char* line) {
 862	uint32_t op1;
 863	uint32_t op2;
 864	line = _hex32(line, &op1);
 865	if (!line) {
 866		return false;
 867	}
 868	while (*line == ' ') {
 869		++line;
 870	}
 871	line = _hex32(line, &op2);
 872	if (!line) {
 873		return false;
 874	}
 875	return GBACheatAddGameShark(cheats, op1, op2);
 876}
 877
 878bool GBACheatAddProActionReplay(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
 879	uint32_t o1 = op1;
 880	uint32_t o2 = op2;
 881	char line[18] = "XXXXXXXX XXXXXXXX";
 882	snprintf(line, sizeof(line), "%08X %08X", op1, op2);
 883	_registerLine(set, line);
 884
 885	switch (set->gsaVersion) {
 886	case 0:
 887		_setGameSharkVersion(set, 3);
 888		// Fall through
 889	case 1:
 890		_decryptGameShark(&o1, &o2, set->gsaSeeds);
 891		return _addPAR3(set, o1, o2);
 892	}
 893	return false;
 894}
 895
 896bool GBACheatAddProActionReplayLine(struct GBACheatSet* cheats, const char* line) {
 897	uint32_t op1;
 898	uint32_t op2;
 899	line = _hex32(line, &op1);
 900	if (!line) {
 901		return false;
 902	}
 903	while (*line == ' ') {
 904		++line;
 905	}
 906	line = _hex32(line, &op2);
 907	if (!line) {
 908		return false;
 909	}
 910	return GBACheatAddProActionReplay(cheats, op1, op2);
 911}
 912
 913bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
 914	uint32_t o1 = op1;
 915	uint32_t o2 = op2;
 916	char line[18] = "XXXXXXXX XXXXXXXX";
 917	snprintf(line, sizeof(line), "%08X %08X", op1, op2);
 918	_registerLine(set, line);
 919
 920	switch (set->gsaVersion) {
 921	case 0:
 922		// Try to detect GameShark version
 923		_decryptGameShark(&o1, &o2, _gsa1S);
 924		if ((o1 & 0xF0000000) == 0xF0000000 && !(o2 & 0xFFFFFCFE)) {
 925			_setGameSharkVersion(set, 1);
 926			return _addGSA1(set, o1, o2);
 927		}
 928		o1 = op1;
 929		o2 = op2;
 930		_decryptGameShark(&o1, &o2, _par3S);
 931		if ((o1 & 0xFE000000) == 0xC4000000 && !(o2 & 0xFFFF0000)) {
 932			_setGameSharkVersion(set, 3);
 933			return _addPAR3(set, o1, o2);
 934		}
 935		break;
 936	case 1:
 937		_decryptGameShark(&o1, &o2, set->gsaSeeds);
 938		return _addGSA1(set, o1, o2);
 939	case 3:
 940		_decryptGameShark(&o1, &o2, set->gsaSeeds);
 941		return _addPAR3(set, o1, o2);
 942	}
 943	return false;
 944}
 945
 946bool GBACheatAutodetectLine(struct GBACheatSet* cheats, const char* line) {
 947	uint32_t op1;
 948	uint32_t op2;
 949	line = _hex32(line, &op1);
 950	if (!line) {
 951		return false;
 952	}
 953	while (*line == ' ') {
 954		++line;
 955	}
 956	line = _hex32(line, &op2);
 957	if (!line) {
 958		return false;
 959	}
 960	return GBACheatAddAutodetect(cheats, op1, op2);
 961}
 962
 963bool GBACheatParseFile(struct GBACheatDevice* device, struct VFile* vf) {
 964	char cheat[MAX_LINE_LENGTH];
 965	struct GBACheatSet* set = 0;
 966	struct GBACheatSet* newSet;
 967	int gsaVersion = 0;
 968	bool nextDisabled = false;
 969	bool reset = false;
 970	while (true) {
 971		size_t i = 0;
 972		ssize_t bytesRead = vf->readline(vf, cheat, sizeof(cheat));
 973		if (bytesRead == 0) {
 974			break;
 975		}
 976		if (bytesRead < 0) {
 977			return false;
 978		}
 979		while (isspace(cheat[i])) {
 980			++i;
 981		}
 982		switch (cheat[i]) {
 983		case '#':
 984			do {
 985				++i;
 986			} while (isspace(cheat[i]));
 987			newSet = malloc(sizeof(*set));
 988			GBACheatSetInit(newSet, &cheat[i]);
 989			newSet->enabled = !nextDisabled;
 990			nextDisabled = false;
 991			if (set) {
 992				GBACheatAddSet(device, set);
 993			}
 994			if (set && !reset) {
 995				GBACheatSetCopyProperties(newSet, set);
 996			} else {
 997				_setGameSharkVersion(newSet, gsaVersion);
 998			}
 999			reset = false;
1000			set = newSet;
1001			break;
1002		case '!':
1003			do {
1004				++i;
1005			} while (isspace(cheat[i]));
1006			if (strncasecmp(&cheat[i], "GSAv", 4) == 0 || strncasecmp(&cheat[i], "PARv", 4) == 0) {
1007				i += 4;
1008				gsaVersion = atoi(&cheat[i]);
1009				break;
1010			}
1011			if (strcasecmp(&cheat[i], "disabled") == 0) {
1012				nextDisabled = true;
1013				break;
1014			}
1015			if (strcasecmp(&cheat[i], "reset") == 0) {
1016				reset = true;
1017				break;
1018			}
1019			break;
1020		default:
1021			if (!set) {
1022				set = malloc(sizeof(*set));
1023				GBACheatSetInit(set, 0);
1024				set->enabled = !nextDisabled;
1025				nextDisabled = false;
1026				_setGameSharkVersion(set, gsaVersion);
1027			}
1028			GBACheatAddLine(set, cheat);
1029			break;
1030		}
1031	}
1032	if (set) {
1033		GBACheatAddSet(device, set);
1034	}
1035	return true;
1036}
1037
1038bool GBACheatSaveFile(struct GBACheatDevice* device, struct VFile* vf) {
1039	static const char lineStart[3] = "# ";
1040	static const char lineEnd = '\n';
1041
1042	struct GBACheatHook* lastHook = 0;
1043
1044	size_t i;
1045	for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
1046		struct GBACheatSet* set = *GBACheatSetsGetPointer(&device->cheats, i);
1047		if (lastHook && set->hook != lastHook) {
1048			static const char* resetDirective = "!reset\n";
1049			vf->write(vf, resetDirective, strlen(resetDirective));
1050		}
1051		switch (set->gsaVersion) {
1052		case 1: {
1053			static const char* versionDirective = "!GSAv1\n";
1054			vf->write(vf, versionDirective, strlen(versionDirective));
1055			break;
1056		}
1057		case 3: {
1058			static const char* versionDirective = "!PARv3\n";
1059			vf->write(vf, versionDirective, strlen(versionDirective));
1060			break;
1061		}
1062		default:
1063			break;
1064		}
1065		lastHook = set->hook;
1066		if (!set->enabled) {
1067			static const char* disabledDirective = "!disabled\n";
1068			vf->write(vf, disabledDirective, strlen(disabledDirective));
1069		}
1070
1071		vf->write(vf, lineStart, 2);
1072		if (set->name) {
1073			vf->write(vf, set->name, strlen(set->name));
1074		}
1075		vf->write(vf, &lineEnd, 1);
1076		size_t c;
1077		for (c = 0; c < StringListSize(&set->lines); ++c) {
1078			const char* line = *StringListGetPointer(&set->lines, c);
1079			vf->write(vf, line, strlen(line));
1080			vf->write(vf, &lineEnd, 1);
1081		}
1082	}
1083	return true;
1084}
1085
1086bool GBACheatAddLine(struct GBACheatSet* cheats, const char* line) {
1087	uint32_t op1;
1088	uint16_t op2;
1089	uint16_t op3;
1090	line = _hex32(line, &op1);
1091	if (!line) {
1092		return false;
1093	}
1094	while (isspace(line[0])) {
1095		++line;
1096	}
1097	line = _hex16(line, &op2);
1098	if (!line) {
1099		return false;
1100	}
1101	if (!line[0] || isspace(line[0])) {
1102		return GBACheatAddCodeBreaker(cheats, op1, op2);
1103	}
1104	line = _hex16(line, &op3);
1105	if (!line) {
1106		return false;
1107	}
1108	uint32_t realOp2 = op2;
1109	realOp2 <<= 16;
1110	realOp2 |= op3;
1111	return GBACheatAddAutodetect(cheats, op1, realOp2);
1112}
1113
1114void GBACheatRefresh(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
1115	if (!cheats->enabled) {
1116		return;
1117	}
1118	bool condition = true;
1119	int conditionRemaining = 0;
1120	int negativeConditionRemaining = 0;
1121	_patchROM(device, cheats);
1122
1123	size_t nCodes = GBACheatListSize(&cheats->list);
1124	size_t i;
1125	for (i = 0; i < nCodes; ++i) {
1126		if (conditionRemaining > 0) {
1127			--conditionRemaining;
1128			if (!condition) {
1129				continue;
1130			}
1131		} else if (negativeConditionRemaining > 0) {
1132			conditionRemaining = negativeConditionRemaining - 1;
1133			negativeConditionRemaining = 0;
1134			condition = !condition;
1135			if (!condition) {
1136				continue;
1137			}
1138		} else {
1139			condition = true;
1140		}
1141		struct GBACheat* cheat = GBACheatListGetPointer(&cheats->list, i);
1142		int32_t value = 0;
1143		int32_t operand = cheat->operand;
1144		uint32_t operationsRemaining = cheat->repeat;
1145		uint32_t address = cheat->address;
1146		bool performAssignment = false;
1147		for (; operationsRemaining; --operationsRemaining) {
1148			switch (cheat->type) {
1149			case CHEAT_ASSIGN:
1150				value = operand;
1151				performAssignment = true;
1152				break;
1153			case CHEAT_ASSIGN_INDIRECT:
1154				value = operand;
1155				address = _readMem(device->p->cpu, address + cheat->addressOffset, 4);
1156				performAssignment = true;
1157				break;
1158			case CHEAT_AND:
1159				value = _readMem(device->p->cpu, address, cheat->width) & operand;
1160				performAssignment = true;
1161				break;
1162			case CHEAT_ADD:
1163				value = _readMem(device->p->cpu, address, cheat->width) + operand;
1164				performAssignment = true;
1165				break;
1166			case CHEAT_OR:
1167				value = _readMem(device->p->cpu, address, cheat->width) | operand;
1168				performAssignment = true;
1169				break;
1170			case CHEAT_IF_EQ:
1171				condition = _readMem(device->p->cpu, address, cheat->width) == operand;
1172				conditionRemaining = cheat->repeat;
1173				negativeConditionRemaining = cheat->negativeRepeat;
1174				break;
1175			case CHEAT_IF_NE:
1176				condition = _readMem(device->p->cpu, address, cheat->width) != operand;
1177				conditionRemaining = cheat->repeat;
1178				negativeConditionRemaining = cheat->negativeRepeat;
1179				break;
1180			case CHEAT_IF_LT:
1181				condition = _readMem(device->p->cpu, address, cheat->width) < operand;
1182				conditionRemaining = cheat->repeat;
1183				negativeConditionRemaining = cheat->negativeRepeat;
1184				break;
1185			case CHEAT_IF_GT:
1186				condition = _readMem(device->p->cpu, address, cheat->width) > operand;
1187				conditionRemaining = cheat->repeat;
1188				negativeConditionRemaining = cheat->negativeRepeat;
1189				break;
1190			case CHEAT_IF_ULT:
1191				condition = (uint32_t) _readMem(device->p->cpu, address, cheat->width) < (uint32_t) operand;
1192				conditionRemaining = cheat->repeat;
1193				negativeConditionRemaining = cheat->negativeRepeat;
1194				break;
1195			case CHEAT_IF_UGT:
1196				condition = (uint32_t) _readMem(device->p->cpu, address, cheat->width) > (uint32_t) operand;
1197				conditionRemaining = cheat->repeat;
1198				negativeConditionRemaining = cheat->negativeRepeat;
1199				break;
1200			case CHEAT_IF_AND:
1201				condition = _readMem(device->p->cpu, address, cheat->width) & operand;
1202				conditionRemaining = cheat->repeat;
1203				negativeConditionRemaining = cheat->negativeRepeat;
1204				break;
1205			case CHEAT_IF_LAND:
1206				condition = _readMem(device->p->cpu, address, cheat->width) && operand;
1207				conditionRemaining = cheat->repeat;
1208				negativeConditionRemaining = cheat->negativeRepeat;
1209				break;
1210			}
1211
1212			if (performAssignment) {
1213				_writeMem(device->p->cpu, address, cheat->width, value);
1214			}
1215
1216			address += cheat->addressOffset;
1217			operand += cheat->operandOffset;
1218		}
1219	}
1220}
1221
1222void GBACheatSetCopyProperties(struct GBACheatSet* newSet, struct GBACheatSet* set) {
1223	newSet->gsaVersion = set->gsaVersion;
1224	memcpy(newSet->gsaSeeds, set->gsaSeeds, sizeof(newSet->gsaSeeds));
1225	if (set->hook) {
1226		if (newSet->hook) {
1227			--newSet->hook->refs;
1228			if (newSet->hook->refs == 0) {
1229				free(newSet->hook);
1230			}
1231		}
1232		newSet->hook = set->hook;
1233		++newSet->hook->refs;
1234	}
1235}
1236
1237void GBACheatDeviceInit(struct ARMCore* cpu, struct ARMComponent* component) {
1238	struct GBACheatDevice* device = (struct GBACheatDevice*) component;
1239	device->p = (struct GBA*) cpu->master;
1240	size_t i;
1241	for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
1242		struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
1243		_addBreakpoint(device, cheats);
1244		_patchROM(device, cheats);
1245	}
1246}
1247
1248void GBACheatDeviceDeinit(struct ARMComponent* component) {
1249	struct GBACheatDevice* device = (struct GBACheatDevice*) component;
1250	size_t i;
1251	for (i = GBACheatSetsSize(&device->cheats); i--;) {
1252		struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
1253		_unpatchROM(device, cheats);
1254		_removeBreakpoint(device, cheats);
1255	}
1256}