Skip to content
This repository was archived by the owner on Mar 18, 2023. It is now read-only.

Commit 00a876d

Browse files
committed
Implement saving value-mapped cheats to database.
1 parent 7a2e972 commit 00a876d

2 files changed

Lines changed: 176 additions & 48 deletions

File tree

src/cheats.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ typedef struct cheatsValueMap {
6969
// Values for each key, corresponding to the nth cstring in keys
7070
// (ex: {0x00000000, 0x00000001})
7171
u32 *values;
72+
// Number of bytes each value occupies
73+
// (ex: 1)
74+
u8 bytesPerEntry;
7275
// Number of values & keys set
7376
// (ex: 2)
7477
u8 numEntries;

src/textcheats.c

Lines changed: 173 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,26 @@ static inline int copyCheatTitleToBuffer(char *buffer, const char *cheatTitle)
109109
return length;
110110
}
111111

112+
// Print value map title in buffer. Returns number of bytes written.
113+
static inline int copyValueMapTitleToBuffer(char *buffer, const char *mapTitle)
114+
{
115+
int length = 0;
116+
buffer[length++] = '[';
117+
strcpy(&buffer[length], mapTitle);
118+
length += strlen(mapTitle);
119+
buffer[length++] = ']';
120+
buffer[length++] = '\n';
121+
122+
return length;
123+
}
124+
125+
// Print value map entry in buffer. Returns number of bytes written
126+
static inline int copyValueMapEntryToBuffer(char *buffer, const char *key, u32 value)
127+
{
128+
int length = sprintf(buffer, "%X = %s\n", value, key);
129+
return length;
130+
}
131+
112132
// Print "<addr> <val>\n" in text buffer. Returns number of bytes written.
113133
static inline int copyCodeToBuffer(char *buffer, u32 addr, u32 val)
114134
{
@@ -134,6 +154,48 @@ static inline int copyCodeToBuffer(char *buffer, u32 addr, u32 val)
134154
return 18; // 8 characters for address + space + 8 characters for value + newline
135155
}
136156

157+
static inline int copyValueMappedCodeToBuffer(char *buffer, u32 addr, u32 val, const char *mapName, int bytesPerEntry)
158+
{
159+
int i;
160+
int index = 0;
161+
const char *hexLUT = "0123456789ABCDEF";
162+
163+
// Convert address to ASCII
164+
for(i = 0; i < 8; i++)
165+
{
166+
u8 nibble = (addr >> (28 - i*4)) & 0xF;
167+
buffer[index++] = hexLUT[nibble];
168+
}
169+
buffer[index++] = ' ';
170+
171+
// Find first non-zero nibble from the right so we can position the map
172+
// reference immediately after it.
173+
int refStart;
174+
for(refStart = (7 - bytesPerEntry*2); refStart >= 0; refStart--)
175+
{
176+
u8 nibble = (val >> (28 - refStart*4)) & 0xF;
177+
if(nibble)
178+
break;
179+
}
180+
181+
refStart++; // Skip past the non-zero nibble
182+
183+
// Convert value to ASCII
184+
for(i = 0; i < refStart; i++)
185+
{
186+
u8 nibble = (val >> (28 - i*4)) & 0xF;
187+
buffer[index++] = hexLUT[nibble];
188+
}
189+
190+
// Write map reference
191+
buffer[index++] = '$';
192+
strcpy(&buffer[index], mapName);
193+
index += strlen(mapName);
194+
buffer[index++] = '\n';
195+
196+
return index;
197+
}
198+
137199
int textCheatsSave(const char *path, const cheatsGame_t *games)
138200
{
139201
if(!path || !games)
@@ -187,6 +249,46 @@ int textCheatsSave(const char *path, const cheatsGame_t *games)
187249
index = copyGameTitleToBuffer(&buf[0], game->title);
188250
}
189251
wroteGameTitle = 1;
252+
253+
int i;
254+
for(i = 0; i < game->numValueMaps; i++)
255+
{
256+
const cheatsValueMap_t *map = game->valueMaps + i;
257+
const char *mapTitle = map->title;
258+
if(index + strlen(mapTitle) + 3 < sizeof(buf)) // 3 = 1 open bracket + 1 close bracket + 1 newline character
259+
{
260+
index += copyValueMapTitleToBuffer(&buf[index], mapTitle);
261+
}
262+
else
263+
{
264+
// Flush buffer to file
265+
fwrite(buf, 1, index, f);
266+
index = copyValueMapTitleToBuffer(&buf[0], mapTitle);
267+
}
268+
269+
int j;
270+
for(j = 0; j < map->numEntries; j++)
271+
{
272+
const char *key = getNthString(map->keys, j);
273+
const u32 value = map->values[j];
274+
int valueLength;
275+
if(value <= 0xFF)
276+
valueLength = 2;
277+
else if(value <= 0xFFFF)
278+
valueLength = 4;
279+
else
280+
valueLength = 8;
281+
if(index + strlen(key) + valueLength + 4) // 4 = 2 spaces + 1 separating character + 1 newline character
282+
{
283+
index += copyValueMapEntryToBuffer(&buf[index], key, value);
284+
}
285+
else
286+
{
287+
fwrite(buf, 1, index, f);
288+
index = copyValueMapEntryToBuffer(&buf[index], key, value);
289+
}
290+
}
291+
}
190292
}
191293

192294
if(index + strlen(cheat->title) + 1 < sizeof(buf))
@@ -200,20 +302,40 @@ int textCheatsSave(const char *path, const cheatsGame_t *games)
200302
index = copyCheatTitleToBuffer(&buf[0], cheat->title);
201303
}
202304

305+
int valueMappedCheat = cheat->type;
306+
203307
int i;
204308
for(i = 0; i < cheat->numCodeLines; i++)
205309
{
206310
u32 addr = game->codeLines[cheat->codeLinesOffset + i];
207311
u32 val = game->codeLines[cheat->codeLinesOffset + i] >> 32;
208-
if(index + 18 < sizeof(buf))
312+
if(!valueMappedCheat || i != cheat->valueMapLine)
209313
{
210-
index += copyCodeToBuffer(&buf[index], addr, val);
314+
if(index + 18 < sizeof(buf))
315+
{
316+
index += copyCodeToBuffer(&buf[index], addr, val);
317+
}
318+
else
319+
{
320+
// Flush buffer to file
321+
fwrite(buf, 1, index, f);
322+
index = copyCodeToBuffer(&buf[0], addr, val);
323+
}
211324
}
212325
else
213326
{
214-
// Flush buffer to file
215-
fwrite(buf, 1, index, f);
216-
index = copyCodeToBuffer(&buf[0], addr, val);
327+
const cheatsValueMap_t *map = &game->valueMaps[cheat->valueMapIndex];
328+
char *mapName = map->title;
329+
330+
if(index + 17 + strlen(mapName) < sizeof(buf)) // worst case: 8 char address + 1 space + 6 char value + $ char + mapName + null char
331+
{
332+
index += copyValueMappedCodeToBuffer(&buf[index], addr, val, mapName, map->bytesPerEntry);
333+
}
334+
else
335+
{
336+
fwrite(buf, 1, index, f);
337+
index = copyValueMappedCodeToBuffer(&buf[index], addr, val, mapName, map->bytesPerEntry);
338+
}
217339
}
218340
}
219341
cheat = cheat->next;
@@ -358,41 +480,41 @@ int textCheatsSaveZip(const char *path, const cheatsGame_t *games)
358480
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
359481

360482
static const unsigned char isCodeDigitLUT[] = {
361-
0,0,0,0,0,0,0,0,0,0,
362-
0,0,0,0,0,0,0,0,0,0,
363-
0,0,0,0,0,0,0,0,0,0,
364-
0,0,
365-
// 0x20: space
366-
1,
367-
0,0,0,0,0,0,0,0,0,0,
368-
0,0,0,0,0,
369-
// 0x30: [0-9]
370-
1,1,1,1,1,1,1,1,1,1,
371-
0,0,0,0,0,0,0,
372-
// 0x41: [A-F]
373-
1,1,1,1,1,1,
374-
0,0,0,0,0,0,0,0,0,0,
375-
0,0,0,0,0,0,0,0,0,0,
376-
0,0,0,0,0,0,
377-
// 0x61: [a-f]
378-
1,1,1,1,1,1,
379-
0,0,0,0,0,0,0,0,0,0,
380-
0,0,0,0,0,0,0,0,0,0,
381-
0,0,0,0,0,0,0,0,0,0,
382-
0,0,0,0,0,0,0,0,0,0,
383-
0,0,0,0,0,0,0,0,0,0,
384-
0,0,0,0,0,0,0,0,0,0,
385-
0,0,0,0,0,0,0,0,0,0,
386-
0,0,0,0,0,0,0,0,0,0,
387-
0,0,0,0,0,0,0,0,0,0,
388-
0,0,0,0,0,0,0,0,0,0,
389-
0,0,0,0,0,0,0,0,0,0,
390-
0,0,0,0,0,0,0,0,0,0,
391-
0,0,0,0,0,0,0,0,0,0,
392-
0,0,0,0,0,0,0,0,0,0,
393-
0,0,0,0,0,0,0,0,0,0,
394-
0,0
395-
};
483+
0,0,0,0,0,0,0,0,0,0,
484+
0,0,0,0,0,0,0,0,0,0,
485+
0,0,0,0,0,0,0,0,0,0,
486+
0,0,
487+
// 0x20: space
488+
1,
489+
0,0,0,0,0,0,0,0,0,0,
490+
0,0,0,0,0,
491+
// 0x30: [0-9]
492+
1,1,1,1,1,1,1,1,1,1,
493+
0,0,0,0,0,0,0,
494+
// 0x41: [A-F]
495+
1,1,1,1,1,1,
496+
0,0,0,0,0,0,0,0,0,0,
497+
0,0,0,0,0,0,0,0,0,0,
498+
0,0,0,0,0,0,
499+
// 0x61: [a-f]
500+
1,1,1,1,1,1,
501+
0,0,0,0,0,0,0,0,0,0,
502+
0,0,0,0,0,0,0,0,0,0,
503+
0,0,0,0,0,0,0,0,0,0,
504+
0,0,0,0,0,0,0,0,0,0,
505+
0,0,0,0,0,0,0,0,0,0,
506+
0,0,0,0,0,0,0,0,0,0,
507+
0,0,0,0,0,0,0,0,0,0,
508+
0,0,0,0,0,0,0,0,0,0,
509+
0,0,0,0,0,0,0,0,0,0,
510+
0,0,0,0,0,0,0,0,0,0,
511+
0,0,0,0,0,0,0,0,0,0,
512+
0,0,0,0,0,0,0,0,0,0,
513+
0,0,0,0,0,0,0,0,0,0,
514+
0,0,0,0,0,0,0,0,0,0,
515+
0,0,0,0,0,0,0,0,0,0,
516+
0,0
517+
};
396518

397519
// Determine token type for line.
398520
static inline int getToken(const unsigned char *line, const int len)
@@ -446,7 +568,7 @@ static inline int getToken(const unsigned char *line, const int len)
446568
numTokens++;
447569

448570
if(numTokens == 15)
449-
return TOKEN_CODE_MAPPED;
571+
return TOKEN_CODE_MAPPED;
450572
}
451573

452574
if(UNLIKELY(len > 3 &&
@@ -729,6 +851,9 @@ static inline int readMapEntryLine(const char *line, int len)
729851
hex[i] = '\0';
730852
u32 value = strtol(hex, NULL, 16);
731853

854+
if(g_ctx.valueMap->bytesPerEntry == 0)
855+
g_ctx.valueMap->bytesPerEntry = i/2 + i%2; // Round up to nearest even number.
856+
732857
// Skip whitespace before seperator (':' or '=')
733858
CONSUME_WHITESPACE(c, end);
734859

@@ -816,13 +941,13 @@ static inline int readMappedCodeLine(const char *line, int len)
816941
};
817942

818943
u64 address = ((u64)lut[(int)line[0]] << 28) |
819-
((u64)lut[(int)line[1]] << 24) |
820-
((u64)lut[(int)line[2]] << 20) |
821-
((u64)lut[(int)line[3]] << 16) |
822-
((u64)lut[(int)line[4]] << 12) |
823-
((u64)lut[(int)line[5]] << 8) |
824-
((u64)lut[(int)line[6]] << 4) |
825-
((u64)lut[(int)line[7]]);
944+
((u64)lut[(int)line[1]] << 24) |
945+
((u64)lut[(int)line[2]] << 20) |
946+
((u64)lut[(int)line[3]] << 16) |
947+
((u64)lut[(int)line[4]] << 12) |
948+
((u64)lut[(int)line[5]] << 8) |
949+
((u64)lut[(int)line[6]] << 4) |
950+
((u64)lut[(int)line[7]]);
826951

827952
const char *c = line + 9;
828953
const char *end = line + len;

0 commit comments

Comments
 (0)