1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
/* Decode a Game Genie code into an M68000 address/data pair.
* The Game Genie code is made of the characters
* ABCDEFGHJKLMNPRSTVWXYZ0123456789 (notice the missing I, O, Q and U).
* Where A = 00000, B = 00001, C = 00010, ... , on to 9 = 11111.
*
* These come out to a very scrambled bit pattern like this:
* (SCRA-MBLE is just an example)
*
* S C R A - M B L E
* 01111 00010 01110 00000 01011 00001 01010 00100
* ijklm nopIJ KLMNO PABCD EFGHd efgha bcQRS TUVWX
*
* Our goal is to rearrange that to this:
*
* 0000 0101 1001 1100 0100 0100 : 1011 0000 0111 1000
* ABCD EFGH IJKL MNOP QRST UVWX : abcd efgh ijkl mnop
*
* which in Hexadecimal is 059C44:B078. Simple, huh? ;)
*
* So, then, we dutifully change memory location 059C44 to B078!
* (of course, that's handled by a different source file :)
*/
#include <stdio.h>
#include <string.h>
#include "decode.h"
static char genie_chars[] = "AaBbCcDdEeFfGgHhJjKkLlMmNnPpRrSsTtVvWwXxYyZz0O1I2233445566778899";
/* genie_decode
* This function converts a Game Genie code to an address:data pair.
* The code is given as an 8-character string, like "BJX0SA1C". It need not
* be null terminated, since only the first 8 characters are taken. It is
* assumed that the code is already made of valid characters, i.e. there are no
* Q's, U's, or symbols. If such a character is
* encountered, the function will return with a warning on stderr.
*
* The resulting address:data pair is returned in the struct patch pointed to
* by result. If an error results, both the address and data will be set to -1.
*/
static void genie_decode(const char* code, struct patch* result)
{
int i = 0, n;
char* x;
for(; i < 8; ++i)
{
/* If strchr returns NULL, we were given a bad character */
if(!(x = strchr(genie_chars, code[i])))
{
result->addr = -1; result->data = -1;
return;
}
n = (x - genie_chars) >> 1;
/* Now, based on which character this is, fit it into the result */
switch(i)
{
case 0:
/* ____ ____ ____ ____ ____ ____ : ____ ____ ABCD E___ */
result->data |= n << 3;
break;
case 1:
/* ____ ____ DE__ ____ ____ ____ : ____ ____ ____ _ABC */
result->data |= n >> 2;
result->addr |= (n & 3) << 14;
break;
case 2:
/* ____ ____ __AB CDE_ ____ ____ : ____ ____ ____ ____ */
result->addr |= n << 9;
break;
case 3:
/* BCDE ____ ____ ___A ____ ____ : ____ ____ ____ ____ */
result->addr |= (n & 0xF) << 20 | (n >> 4) << 8;
break;
case 4:
/* ____ ABCD ____ ____ ____ ____ : ___E ____ ____ ____ */
result->data |= (n & 1) << 12;
result->addr |= (n >> 1) << 16;
break;
case 5:
/* ____ ____ ____ ____ ____ ____ : E___ ABCD ____ ____ */
result->data |= (n & 1) << 15 | (n >> 1) << 8;
break;
case 6:
/* ____ ____ ____ ____ CDE_ ____ : _AB_ ____ ____ ____ */
result->data |= (n >> 3) << 13;
result->addr |= (n & 7) << 5;
break;
case 7:
/* ____ ____ ____ ____ ___A BCDE : ____ ____ ____ ____ */
result->addr |= n;
break;
}
/* Go around again */
}
return;
}
/* "Decode" an address/data pair into a structure. This is for "012345:ABCD"
* type codes. You're more likely to find Genie codes circulating around, but
* there's a chance you could come on to one of these. Which is nice, since
* they're MUCH easier to implement ;) Once again, the input should be depunc-
* tuated already. */
static char hex_chars[] = "00112233445566778899AaBbCcDdEeFf";
static void hex_decode(const char *code, struct patch *result)
{
char *x;
int i;
/* 6 digits for address */
for(i = 0; i < 6; ++i)
{
if(!(x = strchr(hex_chars, code[i])))
{
result->addr = result->data = -1;
return;
}
result->addr = (result->addr << 4) | ((x - hex_chars) >> 1);
}
/* 4 digits for data */
for(i = 6; i < 10; ++i)
{
if(!(x = strchr(hex_chars, code[i])))
{
result->addr = result->data = -1;
return;
}
result->data = (result->data << 4) | ((x - hex_chars) >> 1);
}
}
/* THIS is the function you call from the MegaDrive or whatever. This figures
* out whether it's a genie or hex code, depunctuates it, and calls the proper
* decoder. */
void decode(const char* code, struct patch* result)
{
int len = strlen(code), i, j;
char code_to_pass[16], *x;
const char *ad, *da;
int adl, dal;
/* Initialize the result */
result->addr = result->data = 0;
/* If it's 9 chars long and the 5th is a hyphen, we have a Game Genie
* code. */
if(len == 9 && code[4] == '-')
{
/* Remove the hyphen and pass to genie_decode */
code_to_pass[0] = code[0];
code_to_pass[1] = code[1];
code_to_pass[2] = code[2];
code_to_pass[3] = code[3];
code_to_pass[4] = code[5];
code_to_pass[5] = code[6];
code_to_pass[6] = code[7];
code_to_pass[7] = code[8];
code_to_pass[8] = '\0';
genie_decode(code_to_pass, result);
return;
}
/* Otherwise, we assume it's a hex code.
* Find the colon so we know where address ends and data starts. If there's
* no colon, then we haven't a code at all! */
if(!(x = strchr(code, ':'))) goto bad_code;
ad = code; da = x + 1; adl = x - code; dal = len - adl - 1;
/* If a section is empty or too long, toss it */
if(adl == 0 || adl > 6 || dal == 0 || dal > 4) goto bad_code;
/* Pad the address with zeros, then fill it with the value */
for(i = 0; i < (6 - adl); ++i) code_to_pass[i] = '0';
for(j = 0; i < 6; ++i, ++j) code_to_pass[i] = ad[j];
/* Do the same for data */
for(i = 6; i < (10 - dal); ++i) code_to_pass[i] = '0';
for(j = 0; i < 10; ++i, ++j) code_to_pass[i] = da[j];
code_to_pass[10] = '\0';
/* Decode and goodbye */
hex_decode(code_to_pass, result);
return;
bad_code:
/* AGH! Invalid code! */
result->data = result->addr = -1;
return;
}
|