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