@@ -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.
113133static 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+
137199int 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
360482static 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.
398520static 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