1 /******************************************************************************/
2 /* Mednafen, Cheat Formats Decoding                                           */
3 /******************************************************************************/
4 /* gb.cpp:
5 **  Copyright (C) 2006-2016 Mednafen Team
6 **
7 ** This program is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU General Public License
9 ** as published by the Free Software Foundation; either version 2
10 ** of the License, or (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software Foundation, Inc.,
19 ** 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21 
22 #include <mednafen/mednafen.h>
23 #include <mednafen/mempatcher.h>
24 
25 #include <trio/trio.h>
26 
27 #include "gb.h"
28 
29 namespace Mednafen
30 {
31 
CharToNibble(char thechar)32 static uint8 CharToNibble(char thechar)
33 {
34  const char lut[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
35 
36  thechar = MDFN_azupper(thechar);
37 
38  for(int x = 0; x < 16; x++)
39   if(lut[x] == thechar)
40    return(x);
41 
42  return(0xFF);
43 }
44 
DecodeGG(const std::string & cheat_string,MemoryPatch * patch)45 static bool DecodeGG(const std::string& cheat_string, MemoryPatch* patch)
46 {
47  char str[10];
48  unsigned len;
49 
50  memset(str, 0, sizeof(str));
51 
52  switch(cheat_string.size())
53  {
54   default:
55  	throw(MDFN_Error(0, _("Game Genie code is of an incorrect length.")));
56 	break;
57 
58   case 6:
59   case 9:
60 	strcpy(str, cheat_string.c_str());
61 	break;
62 
63   case 11:
64 	if(cheat_string[7] != '-' && cheat_string[7] != '_' && cheat_string[7] != ' ')
65 	 throw(MDFN_Error(0, _("Game Genie code is malformed.")));
66 
67 	str[6] = cheat_string[8];
68 	str[7] = cheat_string[9];
69 	str[8] = cheat_string[10];
70 
71   case 7:
72 	if(cheat_string[3] != '-' && cheat_string[3] != '_' && cheat_string[3] != ' ')
73 	 throw(MDFN_Error(0, _("Game Genie code is malformed.")));
74 
75  	str[0] = cheat_string[0];
76 	str[1] = cheat_string[1];
77 	str[2] = cheat_string[2];
78 
79 	str[3] = cheat_string[4];
80 	str[4] = cheat_string[5];
81 	str[5] = cheat_string[6];
82 	break;
83  }
84 
85  len = strlen(str);
86 
87  for(unsigned x = 0; x < len; x++)
88  {
89   if(CharToNibble(str[x]) == 0xFF)
90   {
91    if(str[x] & 0x80)
92     throw MDFN_Error(0, _("Invalid character in Game Genie code."));
93    else
94     throw MDFN_Error(0, _("Invalid character in Game Genie code: %c"), str[x]);
95   }
96  }
97 
98  uint32 tmp_address;
99  uint8 tmp_value;
100  uint8 tmp_compare = 0;
101 
102  tmp_address =  (CharToNibble(str[5]) << 12) | (CharToNibble(str[2]) << 8) | (CharToNibble(str[3]) << 4) | (CharToNibble(str[4]) << 0);
103  tmp_address ^= 0xF000;
104  tmp_value = (CharToNibble(str[0]) << 4) | (CharToNibble(str[1]) << 0);
105 
106  if(len == 9)
107  {
108   tmp_compare = (CharToNibble(str[6]) << 4) | (CharToNibble(str[8]) << 0);
109   tmp_compare = (tmp_compare >> 2) | ((tmp_compare << 6) & 0xC0);
110   tmp_compare ^= 0xBA;
111  }
112 
113  patch->addr = tmp_address;
114  patch->val = tmp_value;
115 
116  if(len == 9)
117  {
118   patch->compare = tmp_compare;
119   patch->type = 'C';
120  }
121  else
122  {
123   patch->compare = 0;
124   patch->type = 'S';
125  }
126 
127  patch->length = 1;
128 
129  return(false);
130 }
131 
DecodeGS(const std::string & cheat_string,MemoryPatch * patch)132 static bool DecodeGS(const std::string& cheat_string, MemoryPatch* patch)
133 {
134  if(cheat_string.size() != 8)
135   throw MDFN_Error(0, _("GameShark code is of an incorrect length."));
136 
137  for(unsigned x = 0; x < 8; x++)
138  {
139   if(CharToNibble(cheat_string[x]) == 0xFF)
140   {
141    if(cheat_string[x] & 0x80)
142     throw MDFN_Error(0, _("Invalid character in GameShark code."));
143    else
144     throw MDFN_Error(0, _("Invalid character in GameShark code: %c"), cheat_string[x]);
145   }
146  }
147  uint8 bank = 0;
148  uint16 la = 0;
149 
150 
151  bank = (CharToNibble(cheat_string[0]) << 4) | (CharToNibble(cheat_string[1]) << 0);
152  for(unsigned x = 0; x < 4; x++)
153   la |= CharToNibble(cheat_string[4 + x]) << ((x ^ 1) * 4);
154 
155  if(la >= 0xD000 && la <= 0xDFFF)
156   patch->addr = 0x10000 | ((bank & 0x7) << 12) | (la & 0xFFF);
157  else
158   patch->addr = la;
159 
160  patch->val = (CharToNibble(cheat_string[2]) << 4) | (CharToNibble(cheat_string[3]) << 0);
161 
162  patch->compare = 0;
163  patch->type = 'R';
164  patch->length = 1;
165 
166  return(false);
167 }
168 
169 const std::vector<CheatFormatStruct> CheatFormats_GB =
170 {
171  { "Game Genie", gettext_noop("Genies will eat your goats."), DecodeGG },
172  { "GameShark", gettext_noop("Sharks in your soup."), DecodeGS },
173 };
174 
175 }
176