1 /*  RetroArch - A frontend for libretro.
2  *  Copyright (C) 2010-2014 - Hans-Kristian Arntzen
3  *  Copyright (C) 2011-2017 - Daniel De Matteis
4  *
5  *  RetroArch is free software: you can redistribute it and/or modify it under the terms
6  *  of the GNU General Public License as published by the Free Software Found-
7  *  ation, either version 3 of the License, or (at your option) any later version.
8  *
9  *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10  *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11  *  PURPOSE.  See the GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License along with RetroArch.
14  *  If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include <stdlib.h>
18 #include <stddef.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <math.h>
22 
23 #include <file/config_file.h>
24 #include <file/file_path.h>
25 #include <compat/strl.h>
26 #include <compat/posix_string.h>
27 #include <string/stdstring.h>
28 #include <retro_miscellaneous.h>
29 #include <features/features_cpu.h>
30 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 
35 #ifdef HAVE_MENU
36 #include "menu/menu_driver.h"
37 #endif
38 
39 #ifdef HAVE_CHEEVOS
40 #include "cheevos/cheevos.h"
41 #endif
42 
43 #include "cheat_manager.h"
44 
45 #include "msg_hash.h"
46 #include "configuration.h"
47 #include "retroarch.h"
48 #include "dynamic.h"
49 #include "core.h"
50 #include "verbosity.h"
51 
52 /* TODO/FIXME - public global variables */
53 cheat_manager_t cheat_manager_state;
54 
cheat_manager_get_buf_size(void)55 unsigned cheat_manager_get_buf_size(void)
56 {
57    cheat_manager_t *cheat_st = &cheat_manager_state;
58    return cheat_st->buf_size;
59 }
60 
cheat_manager_get_size(void)61 unsigned cheat_manager_get_size(void)
62 {
63    cheat_manager_t *cheat_st = &cheat_manager_state;
64    return cheat_st->size;
65 }
66 
67 #ifdef HAVE_CHEEVOS
cheat_manager_pause_cheevos(void)68 static void cheat_manager_pause_cheevos(void)
69 {
70    rcheevos_pause_hardcore();
71 
72    runloop_msg_queue_push(msg_hash_to_str(MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
73    RARCH_LOG("%s\n", msg_hash_to_str(MSG_CHEEVOS_HARDCORE_MODE_DISABLED_CHEAT));
74 }
75 #endif
76 
cheat_manager_apply_cheats(void)77 void cheat_manager_apply_cheats(void)
78 {
79    unsigned i, idx           = 0;
80    settings_t *settings      = config_get_ptr();
81    cheat_manager_t *cheat_st = &cheat_manager_state;
82 
83    if (!cheat_st->cheats)
84       return;
85 
86    core_reset_cheat();
87 
88    for (i = 0; i < cheat_st->size; i++)
89    {
90       if (     cheat_st->cheats[i].state
91             && cheat_st->cheats[i].handler == CHEAT_HANDLER_TYPE_EMU)
92       {
93          retro_ctx_cheat_info_t cheat_info;
94 
95          cheat_info.index   = idx++;
96          cheat_info.enabled = true;
97          cheat_info.code    = cheat_st->cheats[i].code;
98 
99          if (!string_is_empty(cheat_info.code))
100             core_set_cheat(&cheat_info);
101       }
102    }
103 
104    if (cheat_st->size > 0 && settings->bools.notification_show_cheats_applied)
105    {
106       runloop_msg_queue_push(msg_hash_to_str(MSG_APPLYING_CHEAT), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
107       RARCH_LOG("%s\n", msg_hash_to_str(MSG_APPLYING_CHEAT));
108    }
109 
110 #ifdef HAVE_CHEEVOS
111    if (idx != 0 && rcheevos_hardcore_active())
112       cheat_manager_pause_cheevos();
113 #endif
114 }
115 
cheat_manager_set_code(unsigned i,const char * str)116 void cheat_manager_set_code(unsigned i, const char *str)
117 {
118    cheat_manager_t *cheat_st = &cheat_manager_state;
119    if (!cheat_st->cheats)
120       return;
121 
122    if (!string_is_empty(str))
123       strcpy(cheat_st->cheats[i].code, str);
124 
125    cheat_st->cheats[i].state = true;
126 }
127 
128 /**
129  * cheat_manager_save:
130  * @path                      : Path to cheats file (relative path).
131  *
132  * Saves cheats to file on disk.
133  *
134  * Returns: true (1) if successful, otherwise false (0).
135  **/
cheat_manager_save(const char * path,const char * cheat_database,bool overwrite)136 bool cheat_manager_save(
137       const char *path,
138       const char *cheat_database,
139       bool overwrite)
140 {
141    bool ret;
142    unsigned i;
143    char cheats_file[PATH_MAX_LENGTH];
144    config_file_t *conf         = NULL;
145    cheat_manager_t *cheat_st   = &cheat_manager_state;
146    unsigned int* data_ptrs[16] = { NULL};
147    char* keys[16] = {
148       (char*)"cheat%u_handler",
149       (char*)"cheat%u_memory_search_size",
150       (char*)"cheat%u_cheat_type",
151       (char*)"cheat%u_value",
152       (char*)"cheat%u_address",
153       (char*)"cheat%u_address_bit_position",
154       (char*)"cheat%u_rumble_type",
155       (char*)"cheat%u_rumble_value",
156       (char*)"cheat%u_rumble_port",
157       (char*)"cheat%u_rumble_primary_strength",
158       (char*)"cheat%u_rumble_primary_duration",
159       (char*)"cheat%u_rumble_secondary_strength",
160       (char*)"cheat%u_rumble_secondary_duration",
161       (char*)"cheat%u_repeat_count",
162       (char*)"cheat%u_repeat_add_to_value",
163       (char*)"cheat%u_repeat_add_to_address"
164    };
165 
166    cheats_file[0] = '\0';
167 
168    if (!cheat_st->cheats || cheat_st->size == 0)
169       return false;
170 
171    if (!cheat_database)
172       strlcpy(cheats_file, path, sizeof(cheats_file));
173    else
174       fill_pathname_join_concat(cheats_file,
175             cheat_database, path,
176             ".cht",
177             sizeof(cheats_file));
178 
179    if (!overwrite)
180       conf = config_file_new_from_path_to_string(cheats_file);
181 
182    if (!conf)
183       if (!(conf = config_file_new_alloc()))
184          return false;
185 
186    conf->guaranteed_no_duplicates = true;
187 
188    config_set_int(conf, "cheats", cheat_st->size);
189 
190    for (i = 0; i < cheat_st->size; i++)
191    {
192       unsigned j;
193       char endian_key[100];
194       char key[256];
195       char desc_key[256];
196       char code_key[256];
197       char enable_key[256];
198 
199       key[0] = endian_key[0] = desc_key[0] = code_key[0] = enable_key[0] = '\0';
200 
201       snprintf(endian_key, sizeof(endian_key), "cheat%u_big_endian", i);
202       snprintf(desc_key, sizeof(desc_key), "cheat%u_desc", i);
203       snprintf(code_key, sizeof(code_key), "cheat%u_code", i);
204       snprintf(enable_key, sizeof(enable_key), "cheat%u_enable", i);
205 
206       if (!string_is_empty(cheat_st->cheats[i].desc))
207          config_set_string(conf, desc_key, cheat_st->cheats[i].desc);
208       else
209          config_set_string(conf, desc_key, cheat_st->cheats[i].code);
210 
211       config_set_string(conf, code_key, cheat_st->cheats[i].code);
212       config_set_bool(conf, enable_key, cheat_st->cheats[i].state);
213       config_set_bool(conf, endian_key, cheat_st->cheats[i].big_endian);
214 
215       data_ptrs[0]  = &cheat_st->cheats[i].handler;
216       data_ptrs[1]  = &cheat_st->cheats[i].memory_search_size;
217       data_ptrs[2]  = &cheat_st->cheats[i].cheat_type;
218       data_ptrs[3]  = &cheat_st->cheats[i].value;
219       data_ptrs[4]  = &cheat_st->cheats[i].address;
220       data_ptrs[5]  = &cheat_st->cheats[i].address_mask;
221       data_ptrs[6]  = &cheat_st->cheats[i].rumble_type;
222       data_ptrs[7]  = &cheat_st->cheats[i].rumble_value;
223       data_ptrs[8]  = &cheat_st->cheats[i].rumble_port;
224       data_ptrs[9]  = &cheat_st->cheats[i].rumble_primary_strength;
225       data_ptrs[10] = &cheat_st->cheats[i].rumble_primary_duration;
226       data_ptrs[11] = &cheat_st->cheats[i].rumble_secondary_strength;
227       data_ptrs[12] = &cheat_st->cheats[i].rumble_secondary_duration;
228       data_ptrs[13] = &cheat_st->cheats[i].repeat_count;
229       data_ptrs[14] = &cheat_st->cheats[i].repeat_add_to_value;
230       data_ptrs[15] = &cheat_st->cheats[i].repeat_add_to_address;
231 
232       for (j = 0; j < 16; j++)
233       {
234          key[0] = '\0';
235          snprintf(key, sizeof(key), keys[j], i);
236          config_set_uint(conf, key, *(data_ptrs[j]));
237       }
238 
239    }
240 
241    ret = config_file_write(conf, cheats_file, true);
242    config_file_free(conf);
243 
244    return ret;
245 }
246 
cheat_manager_copy_idx_to_working(unsigned idx)247 bool cheat_manager_copy_idx_to_working(unsigned idx)
248 {
249    cheat_manager_t *cheat_st   = &cheat_manager_state;
250    if (!cheat_st->cheats || (cheat_st->size < idx + 1))
251       return false;
252 
253    memcpy(&cheat_st->working_cheat,
254          &cheat_st->cheats[idx], sizeof(struct item_cheat));
255 
256    if (cheat_st->cheats[idx].desc)
257       strlcpy(cheat_st->working_desc, cheat_st->cheats[idx].desc, CHEAT_DESC_SCRATCH_SIZE);
258    else
259       cheat_st->working_desc[0] = '\0';
260 
261    if (cheat_st->cheats[idx].code)
262       strlcpy(cheat_st->working_code,
263             cheat_st->cheats[idx].code,
264             CHEAT_CODE_SCRATCH_SIZE);
265    else
266       cheat_st->working_code[0] = '\0';
267 
268    return true;
269 }
270 
cheat_manager_copy_working_to_idx(unsigned idx)271 bool cheat_manager_copy_working_to_idx(unsigned idx)
272 {
273    cheat_manager_t *cheat_st   = &cheat_manager_state;
274    if (!cheat_st->cheats || (cheat_st->size < idx + 1))
275       return false;
276 
277    memcpy(&cheat_st->cheats[idx], &cheat_st->working_cheat,
278          sizeof(struct item_cheat));
279 
280    if (cheat_st->cheats[idx].desc)
281       free(cheat_st->cheats[idx].desc);
282 
283    cheat_st->cheats[idx].desc = strdup(cheat_st->working_desc);
284 
285    if (cheat_st->cheats[idx].code)
286       free(cheat_st->cheats[idx].code);
287 
288    cheat_st->cheats[idx].code = strdup(cheat_st->working_code);
289 
290    return true;
291 }
292 
cheat_manager_free(void)293 static void cheat_manager_free(void)
294 {
295    unsigned i = 0;
296    cheat_manager_t *cheat_st   = &cheat_manager_state;
297 
298    if (cheat_st->cheats)
299    {
300       for (i = 0; i < cheat_st->size; i++)
301       {
302          if (cheat_st->cheats[i].desc)
303             free(cheat_st->cheats[i].desc);
304          if (cheat_st->cheats[i].code)
305             free(cheat_st->cheats[i].code);
306       }
307 
308       free(cheat_st->cheats);
309    }
310 
311    if (cheat_st->prev_memory_buf)
312       free(cheat_st->prev_memory_buf);
313 
314    if (cheat_st->matches)
315       free(cheat_st->matches);
316 
317    if (cheat_st->memory_buf_list)
318       free(cheat_st->memory_buf_list);
319 
320    if (cheat_st->memory_size_list)
321       free(cheat_st->memory_size_list);
322 
323    cheat_st->cheats                    = NULL;
324    cheat_st->size                      = 0;
325    cheat_st->buf_size                  = 0;
326    cheat_st->prev_memory_buf           = NULL;
327    cheat_st->curr_memory_buf           = NULL;
328    cheat_st->memory_buf_list           = NULL;
329    cheat_st->memory_size_list          = NULL;
330    cheat_st->matches                   = NULL;
331    cheat_st->num_memory_buffers        = 0;
332    cheat_st->total_memory_size         = 0;
333    cheat_st->memory_initialized        = false;
334    cheat_st->memory_search_initialized = false;
335 }
336 
cheat_manager_new(unsigned size)337 static void cheat_manager_new(unsigned size)
338 {
339    unsigned i;
340    cheat_manager_t *cheat_st   = &cheat_manager_state;
341 
342    cheat_manager_free();
343 
344    cheat_st->buf_size          = size;
345    cheat_st->size              = size;
346    cheat_st->search_bit_size   = 3;
347    cheat_st->cheats            = (struct item_cheat*)
348          calloc(cheat_st->buf_size, sizeof(struct item_cheat));
349 
350    if (!cheat_st->cheats)
351    {
352       cheat_st->buf_size       = 0;
353       cheat_st->size           = 0;
354       cheat_st->cheats         = NULL;
355       return;
356    }
357 
358    for (i = 0; i < cheat_st->size; i++)
359    {
360       cheat_st->cheats[i].desc                  = NULL;
361       cheat_st->cheats[i].code                  = NULL;
362       cheat_st->cheats[i].state                 = false;
363       cheat_st->cheats[i].repeat_count          = 1;
364       cheat_st->cheats[i].repeat_add_to_value   = 0;
365       cheat_st->cheats[i].repeat_add_to_address = 1;
366    }
367 }
368 
cheat_manager_load_cb_first_pass(char * key,char * value)369 static void cheat_manager_load_cb_first_pass(char *key, char *value)
370 {
371    cheat_manager_t *cheat_st   = &cheat_manager_state;
372 
373    errno                       = 0;
374 
375    if (string_is_equal(key, "cheats"))
376    {
377       cheat_st->loading_cheat_size = (unsigned)strtoul(value, NULL, 0);
378 
379       if (errno != 0)
380          cheat_st->loading_cheat_size = 0;
381    }
382 }
383 
cheat_manager_load_cb_second_pass(char * key,char * value)384 static void cheat_manager_load_cb_second_pass(char *key, char *value)
385 {
386    char cheat_num_str[20];
387    unsigned cheat_num;
388    unsigned cheat_idx;
389    unsigned idx                = 5;
390    size_t key_length           = 0;
391    cheat_manager_t *cheat_st   = &cheat_manager_state;
392 
393    errno                       = 0;
394 
395    if (strncmp(key, "cheat", 5) != 0)
396       return;
397 
398    key_length = strlen((const char*)key);
399 
400    while (idx < key_length && key[idx] >= '0' && key[idx] <= '9' && idx < 24)
401    {
402       cheat_num_str[idx - 5] = key[idx];
403       idx++;
404    }
405 
406    cheat_num_str[idx - 5] = '\0';
407 
408    cheat_num = (unsigned)strtoul(cheat_num_str, NULL, 0);
409 
410    if (cheat_num + cheat_st->loading_cheat_offset >= cheat_st->size)
411       return;
412 
413    key = key + idx + 1;
414 
415    cheat_idx = cheat_num + cheat_st->loading_cheat_offset;
416 
417    if (string_is_equal(key, "address"))
418       cheat_st->cheats[cheat_idx].address = (unsigned)strtoul(value, NULL, 0);
419    else if (string_is_equal(key, "address_bit_position"))
420       cheat_st->cheats[cheat_idx].address_mask = (unsigned)strtoul(value, NULL, 0);
421    else if (string_is_equal(key, "big_endian"))
422       cheat_st->cheats[cheat_idx].big_endian = (string_is_equal(value, "true") || string_is_equal(value, "1"));
423    else if (string_is_equal(key, "cheat_type"))
424       cheat_st->cheats[cheat_idx].cheat_type = (unsigned)strtoul(value, NULL, 0);
425    else if (string_is_equal(key, "code"))
426       cheat_st->cheats[cheat_idx].code = strdup(value);
427    else if (string_is_equal(key, "desc"))
428       cheat_st->cheats[cheat_idx].desc = strdup(value);
429    else if (string_is_equal(key, "enable"))
430       cheat_st->cheats[cheat_idx].state = (string_is_equal(value, "true") || string_is_equal(value, "1"));
431    else if (string_is_equal(key, "handler"))
432       cheat_st->cheats[cheat_idx].handler = (unsigned)strtoul(value, NULL, 0);
433    else if (string_is_equal(key, "memory_search_size"))
434       cheat_st->cheats[cheat_idx].memory_search_size = (unsigned)strtoul(value, NULL, 0);
435    else if (string_starts_with_size(key, "repeat_", STRLEN_CONST("repeat_")))
436    {
437       if (string_is_equal(key, "repeat_add_to_address"))
438          cheat_st->cheats[cheat_idx].repeat_add_to_address = (unsigned)strtoul(value, NULL, 0);
439       else if (string_is_equal(key, "repeat_add_to_value"))
440          cheat_st->cheats[cheat_idx].repeat_add_to_value = (unsigned)strtoul(value, NULL, 0);
441       else if (string_is_equal(key, "repeat_count"))
442          cheat_st->cheats[cheat_idx].repeat_count = (unsigned)strtoul(value, NULL, 0);
443    }
444    else if (string_starts_with_size(key, "rumble", STRLEN_CONST("rumble")))
445    {
446       if (string_is_equal(key, "rumble_port"))
447          cheat_st->cheats[cheat_idx].rumble_port = (unsigned)strtoul(value, NULL, 0);
448       else if (string_is_equal(key, "rumble_primary_duration"))
449          cheat_st->cheats[cheat_idx].rumble_primary_duration = (unsigned)strtoul(value, NULL, 0);
450       else if (string_is_equal(key, "rumble_primary_strength"))
451          cheat_st->cheats[cheat_idx].rumble_primary_strength = (unsigned)strtoul(value, NULL, 0);
452       else if (string_is_equal(key, "rumble_secondary_duration"))
453          cheat_st->cheats[cheat_idx].rumble_secondary_duration = (unsigned)strtoul(value, NULL, 0);
454       else if (string_is_equal(key, "rumble_secondary_strength"))
455          cheat_st->cheats[cheat_idx].rumble_secondary_strength = (unsigned)strtoul(value, NULL, 0);
456       else if (string_is_equal(key, "rumble_type"))
457          cheat_st->cheats[cheat_idx].rumble_type = (unsigned)strtoul(value, NULL, 0);
458       else if (string_is_equal(key, "rumble_value"))
459          cheat_st->cheats[cheat_idx].rumble_value = (unsigned)strtoul(value, NULL, 0);
460    }
461    else if (string_is_equal(key, "value"))
462       cheat_st->cheats[cheat_idx].value = (unsigned)strtoul(value, NULL, 0);
463 }
464 
cheat_manager_load(const char * path,bool append)465 bool cheat_manager_load(const char *path, bool append)
466 {
467    config_file_cb_t cb;
468    unsigned          orig_size = 0;
469    unsigned             cheats = 0;
470    unsigned                  i = 0;
471    config_file_t         *conf = NULL;
472    cheat_manager_t   *cheat_st = &cheat_manager_state;
473 
474    cb.config_file_new_entry_cb = cheat_manager_load_cb_first_pass;
475 
476    cheat_st->loading_cheat_size = 0;
477 
478    conf = config_file_new_with_callback(path, &cb);
479 
480    if (!conf)
481       return false;
482 
483    cheats = cheat_st->loading_cheat_size;
484 
485    if (cheats == 0)
486       goto error;
487 
488    config_file_free(conf);
489    conf = NULL;
490 
491    cheat_manager_alloc_if_empty();
492 
493    if (append)
494    {
495       orig_size = cheat_manager_get_size();
496       if (orig_size == 0)
497          cheat_manager_new(cheats);
498       else
499       {
500          cheats = cheats + orig_size;
501          if (cheat_manager_realloc(cheats, CHEAT_HANDLER_TYPE_EMU)) { }
502       }
503    }
504    else
505    {
506       orig_size = 0;
507       cheat_manager_new(cheats);
508    }
509 
510    for (i = orig_size; cheat_st->cheats && i < cheats; i++)
511    {
512       cheat_st->cheats[i].idx                = i;
513       cheat_st->cheats[i].desc               = NULL;
514       cheat_st->cheats[i].code               = NULL;
515       cheat_st->cheats[i].state              = false;
516       cheat_st->cheats[i].big_endian         = false;
517       cheat_st->cheats[i].cheat_type         = CHEAT_TYPE_SET_TO_VALUE;
518       cheat_st->cheats[i].memory_search_size = 3;
519    }
520 
521    cheat_st->loading_cheat_offset            = orig_size;
522    cb.config_file_new_entry_cb               =
523       cheat_manager_load_cb_second_pass;
524    conf = config_file_new_with_callback(path, &cb);
525 
526    if (!conf)
527       return false;
528 
529    config_file_free(conf);
530 
531    return true;
532 
533 error:
534    config_file_free(conf);
535    return false;
536 }
537 
cheat_manager_realloc(unsigned new_size,unsigned default_handler)538 bool cheat_manager_realloc(unsigned new_size, unsigned default_handler)
539 {
540    unsigned i;
541    unsigned        orig_size = 0;
542    cheat_manager_t *cheat_st = &cheat_manager_state;
543 
544    if (!cheat_st->cheats)
545    {
546       cheat_st->cheats = (struct item_cheat*)
547             calloc(new_size, sizeof(struct item_cheat));
548       orig_size        = 0;
549    }
550    else
551    {
552       struct item_cheat *val = NULL;
553       orig_size              = cheat_st->size;
554 
555       /* if size is decreasing, free the items that will be lost */
556       for (i = new_size; i < orig_size; i++)
557       {
558          if (cheat_st->cheats[i].code)
559             free(cheat_st->cheats[i].code);
560          if (cheat_st->cheats[i].desc)
561             free(cheat_st->cheats[i].desc);
562       }
563 
564       val = (struct item_cheat*)
565             realloc(cheat_st->cheats,
566             new_size * sizeof(struct item_cheat));
567 
568       cheat_st->cheats = val ? val : NULL;
569    }
570 
571    if (!cheat_st->cheats)
572    {
573       cheat_st->buf_size = cheat_st->size = 0;
574       cheat_st->cheats   = NULL;
575       return false;
576    }
577 
578    cheat_st->buf_size = new_size;
579    cheat_st->size     = new_size;
580 
581    for (i = orig_size; i < cheat_st->size; i++)
582    {
583       memset(&cheat_st->cheats[i], 0, sizeof(cheat_st->cheats[i]));
584       cheat_st->cheats[i].state                 = false;
585       cheat_st->cheats[i].handler               = default_handler;
586       cheat_st->cheats[i].cheat_type            = CHEAT_TYPE_SET_TO_VALUE;
587       cheat_st->cheats[i].memory_search_size    = 3;
588       cheat_st->cheats[i].idx                   = i;
589       cheat_st->cheats[i].repeat_count          = 1;
590       cheat_st->cheats[i].repeat_add_to_value   = 0;
591       cheat_st->cheats[i].repeat_add_to_address = 1;
592    }
593 
594    return true;
595 }
596 
cheat_manager_update(cheat_manager_t * handle,unsigned handle_idx)597 void cheat_manager_update(cheat_manager_t *handle, unsigned handle_idx)
598 {
599    char msg[256];
600 
601    if (!handle || !handle->cheats || handle->size == 0)
602       return;
603 
604    snprintf(msg, sizeof(msg),
605          "Cheat: #%u [%s]: %s",
606          handle_idx,
607          handle->cheats[handle_idx].state ? "ON" : "OFF",
608          handle->cheats[handle_idx].desc
609          ? (handle->cheats[handle_idx].desc)
610          : (handle->cheats[handle_idx].code)
611          );
612    runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
613    RARCH_LOG("%s\n", msg);
614 }
615 
cheat_manager_toggle_index(bool apply_cheats_after_toggle,unsigned i)616 void cheat_manager_toggle_index(bool apply_cheats_after_toggle,
617       unsigned i)
618 {
619    cheat_manager_t *cheat_st = &cheat_manager_state;
620    if (!cheat_st->cheats || cheat_st->size == 0)
621       return;
622 
623    cheat_st->cheats[i].state = !cheat_st->cheats[i].state;
624    cheat_manager_update(cheat_st, i);
625 
626    if (apply_cheats_after_toggle)
627       cheat_manager_apply_cheats();
628 }
629 
cheat_manager_toggle(void)630 void cheat_manager_toggle(void)
631 {
632    cheat_manager_t *cheat_st = &cheat_manager_state;
633    if (!cheat_st->cheats || cheat_st->size == 0)
634       return;
635 
636    cheat_st->cheats[cheat_st->ptr].state ^= true;
637    cheat_manager_apply_cheats();
638    cheat_manager_update(cheat_st, cheat_st->ptr);
639 }
640 
cheat_manager_index_next(void)641 void cheat_manager_index_next(void)
642 {
643    cheat_manager_t *cheat_st = &cheat_manager_state;
644    if (!cheat_st->cheats || cheat_st->size == 0)
645       return;
646 
647    cheat_st->ptr = (cheat_st->ptr + 1) % cheat_st->size;
648    cheat_manager_update(cheat_st, cheat_st->ptr);
649 }
650 
cheat_manager_index_prev(void)651 void cheat_manager_index_prev(void)
652 {
653    cheat_manager_t *cheat_st = &cheat_manager_state;
654    if (!cheat_st->cheats || cheat_st->size == 0)
655       return;
656 
657    if (cheat_st->ptr == 0)
658       cheat_st->ptr = cheat_st->size - 1;
659    else
660       cheat_st->ptr--;
661 
662    cheat_manager_update(cheat_st, cheat_st->ptr);
663 }
664 
cheat_manager_get_code(unsigned i)665 const char *cheat_manager_get_code(unsigned i)
666 {
667    cheat_manager_t *cheat_st = &cheat_manager_state;
668    if (!cheat_st->cheats)
669       return NULL;
670    return cheat_st->cheats[i].code;
671 }
672 
cheat_manager_get_desc(unsigned i)673 const char *cheat_manager_get_desc(unsigned i)
674 {
675    cheat_manager_t *cheat_st = &cheat_manager_state;
676    if (!cheat_st->cheats)
677       return NULL;
678    return cheat_st->cheats[i].desc;
679 }
680 
cheat_manager_get_code_state(unsigned i)681 bool cheat_manager_get_code_state(unsigned i)
682 {
683    cheat_manager_t *cheat_st = &cheat_manager_state;
684    if (!cheat_st->cheats)
685       return false;
686    return cheat_st->cheats[i].state;
687 }
688 
cheat_manager_get_game_specific_filename(char * s,size_t len,const char * path_cheat_database,bool saving)689 static bool cheat_manager_get_game_specific_filename(
690       char *s, size_t len,
691       const char *path_cheat_database,
692       bool saving)
693 {
694    char s1[PATH_MAX_LENGTH];
695    struct retro_system_info system_info;
696    global_t *global        = global_get_ptr();
697    const char *core_name   = NULL;
698    const char *game_name   = NULL;
699 
700    s1[0]                   = '\0';
701 
702    if (!global || !core_get_system_info(&system_info))
703       return false;
704 
705    core_name = system_info.library_name;
706    game_name = path_basename_nocompression(global->name.cheatfile);
707 
708    if (string_is_empty(path_cheat_database) ||
709          string_is_empty(core_name) ||
710          string_is_empty(game_name))
711       return false;
712 
713    s[0] = '\0';
714 
715    fill_pathname_join(s1,
716          path_cheat_database, core_name,
717          sizeof(s1));
718 
719    if (saving)
720    {
721       /* Check if directory is valid, if not, create it */
722       if (!path_is_valid(s1))
723          path_mkdir(s1);
724    }
725 
726    fill_pathname_join(s, s1, game_name, len);
727 
728    return true;
729 }
730 
cheat_manager_load_game_specific_cheats(const char * path_cheat_database)731 void cheat_manager_load_game_specific_cheats(const char *path_cheat_database)
732 {
733    char cheat_file[PATH_MAX_LENGTH];
734 
735    if (cheat_manager_get_game_specific_filename(
736             cheat_file, sizeof(cheat_file),
737             path_cheat_database,
738             false))
739    {
740       if (cheat_manager_load(cheat_file, true))
741          RARCH_LOG("[Cheats]: Load game-specific cheatfile: %s\n", cheat_file);
742    }
743 }
744 
cheat_manager_save_game_specific_cheats(const char * path_cheat_database)745 void cheat_manager_save_game_specific_cheats(const char *path_cheat_database)
746 {
747    char cheat_file[PATH_MAX_LENGTH];
748 
749    if (cheat_manager_get_game_specific_filename(
750             cheat_file, sizeof(cheat_file),
751             path_cheat_database,
752             true))
753    {
754       if (cheat_manager_save(cheat_file, NULL, true))
755          RARCH_LOG("[Cheats]: Save game-specific cheatfile: %s\n", cheat_file);
756    }
757 }
758 
cheat_manager_state_free(void)759 void cheat_manager_state_free(void)
760 {
761    cheat_manager_free();
762 }
763 
cheat_manager_alloc_if_empty(void)764 bool cheat_manager_alloc_if_empty(void)
765 {
766    cheat_manager_t *cheat_st = &cheat_manager_state;
767    if (!cheat_st->cheats)
768       cheat_manager_new(0);
769 
770    return true;
771 }
772 
cheat_manager_initialize_memory(rarch_setting_t * setting,size_t idx,bool wraparound)773 int cheat_manager_initialize_memory(rarch_setting_t *setting, size_t idx, bool wraparound)
774 {
775    unsigned i;
776    retro_ctx_memory_info_t meminfo;
777    bool refresh                           = false;
778    bool is_search_initialization          = (setting != NULL);
779    rarch_system_info_t *system            = runloop_get_system_info();
780    unsigned offset                        = 0;
781    cheat_manager_t              *cheat_st = &cheat_manager_state;
782 
783    cheat_st->num_memory_buffers           = 0;
784    cheat_st->total_memory_size            = 0;
785    cheat_st->curr_memory_buf              = NULL;
786 
787    if (cheat_st->memory_buf_list)
788    {
789       free(cheat_st->memory_buf_list);
790       cheat_st->memory_buf_list = NULL;
791    }
792 
793    if (cheat_st->memory_size_list)
794    {
795       free(cheat_st->memory_size_list);
796       cheat_st->memory_size_list = NULL;
797    }
798 
799    if (system && system->mmaps.num_descriptors > 0)
800    {
801       for (i = 0; i < system->mmaps.num_descriptors; i++)
802       {
803          if ((system->mmaps.descriptors[i].core.flags
804                   & RETRO_MEMDESC_SYSTEM_RAM) != 0 &&
805                system->mmaps.descriptors[i].core.ptr &&
806                system->mmaps.descriptors[i].core.len > 0)
807          {
808             cheat_st->num_memory_buffers++;
809 
810             if (!cheat_st->memory_buf_list)
811                cheat_st->memory_buf_list = (uint8_t**)calloc(1, sizeof(uint8_t *));
812             else
813                cheat_st->memory_buf_list = (uint8_t**)realloc(
814                      cheat_st->memory_buf_list, sizeof(uint8_t *) * cheat_st->num_memory_buffers);
815 
816             if (!cheat_st->memory_size_list)
817                cheat_st->memory_size_list = (unsigned*)calloc(1, sizeof(unsigned));
818             else
819             {
820                unsigned *val = (unsigned*)realloc(
821                      cheat_st->memory_size_list,
822                      sizeof(unsigned) *
823                      cheat_st->num_memory_buffers);
824 
825                if (val)
826                   cheat_st->memory_size_list = val;
827             }
828 
829             cheat_st->memory_buf_list[cheat_st->num_memory_buffers - 1] = (uint8_t*)system->mmaps.descriptors[i].core.ptr;
830             cheat_st->memory_size_list[cheat_st->num_memory_buffers - 1] = (unsigned)system->mmaps.descriptors[i].core.len;
831             cheat_st->total_memory_size += system->mmaps.descriptors[i].core.len;
832 
833             if (!cheat_st->curr_memory_buf)
834                cheat_st->curr_memory_buf = (uint8_t*)system->mmaps.descriptors[i].core.ptr;
835          }
836       }
837    }
838 
839    if (cheat_st->num_memory_buffers == 0)
840    {
841       meminfo.id = RETRO_MEMORY_SYSTEM_RAM;
842       if (!core_get_memory(&meminfo))
843       {
844          runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_INIT_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
845          return 0;
846       }
847 
848       if (meminfo.size == 0)
849          return 0;
850 
851       cheat_st->memory_buf_list     = (uint8_t**)
852             calloc(1, sizeof(uint8_t *));
853       cheat_st->memory_size_list    = (unsigned*)
854             calloc(1, sizeof(unsigned));
855       cheat_st->num_memory_buffers  = 1;
856       cheat_st->memory_buf_list[0]  = (uint8_t*)meminfo.data;
857       cheat_st->memory_size_list[0] = (unsigned)meminfo.size;
858       cheat_st->total_memory_size   = (unsigned)meminfo.size;
859       cheat_st->curr_memory_buf     = (uint8_t*)meminfo.data;
860 
861    }
862 
863    cheat_st->num_matches = (cheat_st->total_memory_size * 8) / (1 << cheat_st->search_bit_size);
864 
865 #if 0
866    /* Ensure we're aligned on 4-byte boundary */
867    if (meminfo.size % 4 > 0)
868       cheat_st->total_memory_size = cheat_st->total_memory_size + (4 - (meminfo.size % 4));
869 #endif
870 
871    if (is_search_initialization)
872    {
873       if (cheat_st->prev_memory_buf)
874       {
875          free(cheat_st->prev_memory_buf);
876          cheat_st->prev_memory_buf = NULL;
877       }
878 
879       cheat_st->prev_memory_buf = (uint8_t*)calloc(
880             cheat_st->total_memory_size, sizeof(uint8_t));
881 
882       if (!cheat_st->prev_memory_buf)
883       {
884          runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_INIT_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
885          return 0;
886       }
887 
888       if (cheat_st->matches)
889       {
890          free(cheat_st->matches);
891          cheat_st->matches = NULL;
892       }
893 
894       cheat_st->matches = (uint8_t*)calloc(
895             cheat_st->total_memory_size, sizeof(uint8_t));
896 
897       if (!cheat_st->matches)
898       {
899          free(cheat_st->prev_memory_buf);
900          cheat_st->prev_memory_buf = NULL;
901          runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_INIT_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
902          return 0;
903       }
904 
905       memset(cheat_st->matches, 0xFF, cheat_st->total_memory_size);
906 
907       offset = 0;
908 
909       for (i = 0; i < cheat_st->num_memory_buffers; i++)
910       {
911          memcpy(cheat_st->prev_memory_buf + offset,
912                cheat_st->memory_buf_list[i],
913                cheat_st->memory_size_list[i]);
914          offset += cheat_st->memory_size_list[i];
915       }
916 
917       cheat_st->memory_search_initialized = true;
918    }
919 
920    cheat_st->memory_initialized = true;
921 
922    runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_INIT_SUCCESS), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
923 
924 #ifdef HAVE_MENU
925    if (!wraparound)
926    {
927       menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
928       menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
929    }
930 #endif
931 
932    return 0;
933 }
934 
translate_address(unsigned address,unsigned char ** curr)935 static unsigned translate_address(unsigned address, unsigned char **curr)
936 {
937    unsigned             offset = 0;
938    unsigned                  i = 0;
939    cheat_manager_t   *cheat_st = &cheat_manager_state;
940 
941    for (i = 0; i < cheat_st->num_memory_buffers; i++)
942    {
943       if ((address >= offset) && (address < offset + cheat_st->memory_size_list[i]))
944       {
945          *curr = cheat_st->memory_buf_list[i];
946          break;
947       }
948       else
949          offset += cheat_st->memory_size_list[i];
950    }
951 
952    return offset;
953 }
954 
cheat_manager_setup_search_meta(unsigned int bitsize,unsigned int * bytes_per_item,unsigned int * mask,unsigned int * bits)955 static void cheat_manager_setup_search_meta(
956       unsigned int bitsize,
957       unsigned int *bytes_per_item,
958       unsigned int *mask,
959       unsigned int *bits)
960 {
961    switch (bitsize)
962    {
963       case 0:
964          *bytes_per_item = 1;
965          *bits           = 1;
966          *mask           = 0x01;
967          break;
968       case 1:
969          *bytes_per_item = 1;
970          *bits           = 2;
971          *mask           = 0x03;
972          break;
973       case 2:
974          *bytes_per_item = 1;
975          *bits           = 4;
976          *mask           = 0x0F;
977          break;
978       case 3:
979          *bytes_per_item = 1;
980          *bits           = 8;
981          *mask           = 0xFF;
982          break;
983       case 4:
984          *bytes_per_item = 2;
985          *bits           = 8;
986          *mask           = 0xFFFF;
987          break;
988       case 5:
989          *bytes_per_item = 4;
990          *bits           = 8;
991          *mask           = 0xFFFFFFFF;
992          break;
993    }
994 }
995 
cheat_manager_search(enum cheat_search_type search_type)996 static int cheat_manager_search(enum cheat_search_type search_type)
997 {
998    char msg[100];
999    cheat_manager_t   *cheat_st = &cheat_manager_state;
1000    unsigned char *curr         = cheat_st->curr_memory_buf;
1001    unsigned char *prev         = cheat_st->prev_memory_buf;
1002    unsigned int idx            = 0;
1003    unsigned int curr_val       = 0;
1004    unsigned int prev_val       = 0;
1005    unsigned int mask           = 0;
1006    unsigned int bytes_per_item = 1;
1007    unsigned int bits           = 8;
1008    unsigned int offset         = 0;
1009    unsigned int i              = 0;
1010    bool refresh                = false;
1011 
1012    if (cheat_st->num_memory_buffers == 0)
1013    {
1014       runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_NOT_INITIALIZED), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1015       return 0;
1016    }
1017 
1018    cheat_manager_setup_search_meta(cheat_st->search_bit_size, &bytes_per_item, &mask, &bits);
1019 
1020    /* little endian FF000000 = 256 */
1021    for (idx = 0; idx < cheat_st->total_memory_size; idx = idx + bytes_per_item)
1022    {
1023       unsigned byte_part;
1024 
1025       offset = translate_address(idx, &curr);
1026 
1027       switch (bytes_per_item)
1028       {
1029          case 2:
1030             curr_val = cheat_st->big_endian ?
1031                (*(curr + idx - offset) * 256) + *(curr + idx + 1 - offset) :
1032                *(curr + idx - offset) + (*(curr + idx + 1 - offset) * 256);
1033             prev_val = cheat_st->big_endian ?
1034                (*(prev + idx) * 256) + *(prev + idx + 1) :
1035                *(prev + idx) + (*(prev + idx + 1) * 256);
1036             break;
1037          case 4:
1038             curr_val = cheat_st->big_endian ?
1039                (*(curr + idx - offset) * 256 * 256 * 256) + (*(curr + idx + 1 - offset) * 256 * 256) + (*(curr + idx + 2 - offset) * 256) + *(curr + idx + 3 - offset) :
1040                *(curr + idx - offset) + (*(curr + idx + 1 - offset) * 256) + (*(curr + idx + 2 - offset) * 256 * 256) + (*(curr + idx + 3 - offset) * 256 * 256 * 256);
1041             prev_val = cheat_st->big_endian ?
1042                (*(prev + idx) * 256 * 256 * 256) + (*(prev + idx + 1) * 256 * 256) + (*(prev + idx + 2) * 256) + *(prev + idx + 3) :
1043                *(prev + idx) + (*(prev + idx + 1) * 256) + (*(prev + idx + 2) * 256 * 256) + (*(prev + idx + 3) * 256 * 256 * 256);
1044             break;
1045          case 1:
1046          default:
1047             curr_val = *(curr - offset + idx);
1048             prev_val = *(prev + idx);
1049             break;
1050       }
1051 
1052       for (byte_part = 0; byte_part < 8 / bits; byte_part++)
1053       {
1054          unsigned int curr_subval = (curr_val >> (byte_part * bits)) & mask;
1055          unsigned int prev_subval = (prev_val >> (byte_part * bits)) & mask;
1056          unsigned int prev_match;
1057 
1058          if (bits < 8)
1059             prev_match = *(cheat_st->matches + idx) & (mask << (byte_part * bits));
1060          else
1061             prev_match = *(cheat_st->matches + idx);
1062 
1063          if (prev_match > 0)
1064          {
1065             bool match = false;
1066             switch (search_type)
1067             {
1068                case CHEAT_SEARCH_TYPE_EXACT:
1069                   match = (curr_subval == cheat_st->search_exact_value);
1070                   break;
1071                case CHEAT_SEARCH_TYPE_LT:
1072                   match = (curr_subval < prev_subval);
1073                   break;
1074                case CHEAT_SEARCH_TYPE_GT:
1075                   match = (curr_subval > prev_subval);
1076                   break;
1077                case CHEAT_SEARCH_TYPE_LTE:
1078                   match = (curr_subval <= prev_subval);
1079                   break;
1080                case CHEAT_SEARCH_TYPE_GTE:
1081                   match = (curr_subval >= prev_subval);
1082                   break;
1083                case CHEAT_SEARCH_TYPE_EQ:
1084                   match = (curr_subval == prev_subval);
1085                   break;
1086                case CHEAT_SEARCH_TYPE_NEQ:
1087                   match = (curr_subval != prev_subval);
1088                   break;
1089                case CHEAT_SEARCH_TYPE_EQPLUS:
1090                   match = (curr_subval == prev_subval + cheat_st->search_eqplus_value);
1091                   break;
1092                case CHEAT_SEARCH_TYPE_EQMINUS:
1093                   match = (curr_subval == prev_subval - cheat_st->search_eqminus_value);
1094                   break;
1095             }
1096 
1097             if (!match)
1098             {
1099                if (bits < 8)
1100                   *(cheat_st->matches + idx) = *(cheat_st->matches + idx) &
1101                      ((~(mask << (byte_part * bits))) & 0xFF);
1102                else
1103                   memset(cheat_st->matches + idx, 0, bytes_per_item);
1104                if (cheat_st->num_matches > 0)
1105                   cheat_st->num_matches--;
1106             }
1107          }
1108       }
1109    }
1110 
1111    offset = 0;
1112 
1113    for (i = 0; i < cheat_st->num_memory_buffers; i++)
1114    {
1115       memcpy(cheat_st->prev_memory_buf + offset, cheat_st->memory_buf_list[i], cheat_st->memory_size_list[i]);
1116       offset += cheat_st->memory_size_list[i];
1117    }
1118 
1119    snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_CHEAT_SEARCH_FOUND_MATCHES), cheat_st->num_matches);
1120    msg[sizeof(msg) - 1] = 0;
1121 
1122    runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1123 
1124 #ifdef HAVE_MENU
1125    menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
1126    menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
1127 #endif
1128    return 0;
1129 }
1130 
cheat_manager_search_exact(rarch_setting_t * setting,size_t idx,bool wraparound)1131 int cheat_manager_search_exact(rarch_setting_t *setting, size_t idx, bool wraparound)
1132 {
1133    return cheat_manager_search(CHEAT_SEARCH_TYPE_EXACT);
1134 }
1135 
cheat_manager_search_lt(rarch_setting_t * setting,size_t idx,bool wraparound)1136 int cheat_manager_search_lt(rarch_setting_t *setting, size_t idx, bool wraparound)
1137 {
1138    return cheat_manager_search(CHEAT_SEARCH_TYPE_LT);
1139 }
1140 
cheat_manager_search_gt(rarch_setting_t * setting,size_t idx,bool wraparound)1141 int cheat_manager_search_gt(rarch_setting_t *setting, size_t idx, bool wraparound)
1142 {
1143    return cheat_manager_search(CHEAT_SEARCH_TYPE_GT);
1144 }
1145 
cheat_manager_search_lte(rarch_setting_t * setting,size_t idx,bool wraparound)1146 int cheat_manager_search_lte(rarch_setting_t *setting, size_t idx, bool wraparound)
1147 {
1148    return cheat_manager_search(CHEAT_SEARCH_TYPE_LTE);
1149 }
1150 
cheat_manager_search_gte(rarch_setting_t * setting,size_t idx,bool wraparound)1151 int cheat_manager_search_gte(rarch_setting_t *setting, size_t idx, bool wraparound)
1152 {
1153    return cheat_manager_search(CHEAT_SEARCH_TYPE_GTE);
1154 }
1155 
cheat_manager_search_eq(rarch_setting_t * setting,size_t idx,bool wraparound)1156 int cheat_manager_search_eq(rarch_setting_t *setting, size_t idx, bool wraparound)
1157 {
1158    return cheat_manager_search(CHEAT_SEARCH_TYPE_EQ);
1159 }
1160 
cheat_manager_search_neq(rarch_setting_t * setting,size_t idx,bool wraparound)1161 int cheat_manager_search_neq(rarch_setting_t *setting, size_t idx, bool wraparound)
1162 {
1163    return cheat_manager_search(CHEAT_SEARCH_TYPE_NEQ);
1164 }
1165 
cheat_manager_search_eqplus(rarch_setting_t * setting,size_t idx,bool wraparound)1166 int cheat_manager_search_eqplus(rarch_setting_t *setting, size_t idx, bool wraparound)
1167 {
1168    return cheat_manager_search(CHEAT_SEARCH_TYPE_EQPLUS);
1169 }
1170 
cheat_manager_search_eqminus(rarch_setting_t * setting,size_t idx,bool wraparound)1171 int cheat_manager_search_eqminus(rarch_setting_t *setting, size_t idx, bool wraparound)
1172 {
1173    return cheat_manager_search(CHEAT_SEARCH_TYPE_EQMINUS);
1174 }
1175 
cheat_manager_get_state_search_size(unsigned search_size)1176 unsigned cheat_manager_get_state_search_size(unsigned search_size)
1177 {
1178    uint32_t n[] = {1,3,15,255,0x0000ffff,0xffffffff};
1179    return n[search_size];
1180 }
1181 
cheat_manager_add_new_code(unsigned int memory_search_size,unsigned int address,unsigned int address_mask,bool big_endian,unsigned int value)1182 bool cheat_manager_add_new_code(unsigned int memory_search_size, unsigned int address, unsigned int address_mask,
1183       bool big_endian, unsigned int value)
1184 {
1185    cheat_manager_t   *cheat_st = &cheat_manager_state;
1186    int                new_size = cheat_manager_get_size() + 1;
1187 
1188    if (!cheat_manager_realloc(new_size, CHEAT_HANDLER_TYPE_RETRO))
1189       return false;
1190 
1191    cheat_st->cheats[cheat_st->size - 1].address = address;
1192    cheat_st->cheats[cheat_st->size - 1].address_mask = address_mask;
1193    cheat_st->cheats[cheat_st->size - 1].memory_search_size = memory_search_size;
1194    cheat_st->cheats[cheat_st->size - 1].value = value;
1195    cheat_st->cheats[cheat_st->size - 1].big_endian = big_endian;
1196 
1197    return true;
1198 }
1199 
cheat_manager_add_matches(const char * path,const char * label,unsigned type,size_t menuidx,size_t entry_idx)1200 int cheat_manager_add_matches(const char *path,
1201       const char *label, unsigned type, size_t menuidx, size_t entry_idx)
1202 {
1203    char msg[100];
1204    bool                refresh = false;
1205    unsigned          byte_part = 0;
1206    unsigned            int idx = 0;
1207    unsigned           int mask = 0;
1208    unsigned int bytes_per_item = 1;
1209    unsigned           int bits = 8;
1210    unsigned       int curr_val = 0;
1211    unsigned      int num_added = 0;
1212    unsigned         int offset = 0;
1213    cheat_manager_t   *cheat_st = &cheat_manager_state;
1214    unsigned char         *curr = cheat_st->curr_memory_buf;
1215 
1216    if (cheat_st->num_matches + cheat_st->size > 100)
1217    {
1218       runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_TOO_MANY), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1219       return 0;
1220    }
1221    cheat_manager_setup_search_meta(cheat_st->search_bit_size, &bytes_per_item, &mask, &bits);
1222 
1223    for (idx = 0; idx < cheat_st->total_memory_size; idx = idx + bytes_per_item)
1224    {
1225       offset = translate_address(idx, &curr);
1226 
1227       switch (bytes_per_item)
1228       {
1229          case 2:
1230             curr_val = cheat_st->big_endian ?
1231                (*(curr + idx - offset) * 256) + *(curr + idx + 1 - offset) :
1232                *(curr + idx - offset) + (*(curr + idx + 1 - offset) * 256);
1233             break;
1234          case 4:
1235             curr_val = cheat_st->big_endian ?
1236                (*(curr + idx - offset) * 256 * 256 * 256) + (*(curr + idx + 1 - offset) * 256 * 256) + (*(curr + idx + 2 - offset) * 256) + *(curr + idx + 3 - offset) :
1237                *(curr + idx - offset) + (*(curr + idx + 1 - offset) * 256) + (*(curr + idx + 2 - offset) * 256 * 256) + (*(curr + idx + 3 - offset) * 256 * 256 * 256);
1238             break;
1239          case 1:
1240          default:
1241             curr_val = *(curr - offset + idx);
1242             break;
1243       }
1244       for (byte_part = 0; byte_part < 8 / bits; byte_part++)
1245       {
1246          unsigned int prev_match;
1247 
1248          if (bits < 8)
1249          {
1250             prev_match = *(cheat_st->matches + idx) & (mask << (byte_part * bits));
1251             if (prev_match)
1252             {
1253                if (!cheat_manager_add_new_code(cheat_st->search_bit_size, idx, (mask << (byte_part * bits)),
1254                         cheat_st->big_endian, curr_val))
1255                {
1256                   runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1257                   return 0;
1258                }
1259                num_added++;
1260             }
1261          }
1262          else
1263          {
1264             prev_match = *(cheat_st->matches + idx);
1265             if (prev_match)
1266             {
1267                if (!cheat_manager_add_new_code(cheat_st->search_bit_size, idx, 0xFF,
1268                         cheat_st->big_endian, curr_val))
1269                {
1270                   runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1271                   return 0;
1272                }
1273                num_added++;
1274             }
1275          }
1276 
1277       }
1278    }
1279 
1280    snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_SUCCESS), cheat_st->num_matches);
1281    msg[sizeof(msg) - 1] = 0;
1282 
1283    runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1284 
1285 #ifdef HAVE_MENU
1286    menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
1287    menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
1288 #endif
1289 
1290    return 0;
1291 }
1292 
cheat_manager_apply_rumble(struct item_cheat * cheat,unsigned int curr_value)1293 void cheat_manager_apply_rumble(struct item_cheat *cheat, unsigned int curr_value)
1294 {
1295    bool rumble               = false;
1296    retro_time_t current_time = cpu_features_get_time_usec();
1297 
1298    switch (cheat->rumble_type)
1299    {
1300       case RUMBLE_TYPE_DISABLED:
1301          return;
1302       case RUMBLE_TYPE_CHANGES:
1303          rumble = (curr_value != cheat->rumble_prev_value);
1304          break;
1305       case RUMBLE_TYPE_DOES_NOT_CHANGE:
1306          rumble = (curr_value == cheat->rumble_prev_value);
1307          break;
1308       case RUMBLE_TYPE_INCREASE:
1309          rumble = (curr_value > cheat->rumble_prev_value);
1310          break;
1311       case RUMBLE_TYPE_DECREASE:
1312          rumble = (curr_value < cheat->rumble_prev_value);
1313          break;
1314       case RUMBLE_TYPE_EQ_VALUE:
1315          rumble = (curr_value == cheat->rumble_value);
1316          break;
1317       case RUMBLE_TYPE_NEQ_VALUE:
1318          rumble = (curr_value != cheat->rumble_value);
1319          break;
1320       case RUMBLE_TYPE_LT_VALUE:
1321          rumble = (curr_value < cheat->rumble_value);
1322          break;
1323       case RUMBLE_TYPE_GT_VALUE:
1324          rumble = (curr_value > cheat->rumble_value);
1325          break;
1326       case RUMBLE_TYPE_INCREASE_BY_VALUE:
1327          rumble = (curr_value == cheat->rumble_prev_value + cheat->rumble_value);
1328          break;
1329       case RUMBLE_TYPE_DECREASE_BY_VALUE:
1330          rumble = (curr_value == cheat->rumble_prev_value - cheat->rumble_value);
1331          break;
1332    }
1333 
1334    cheat->rumble_prev_value = curr_value;
1335 
1336    /* Give the emulator enough time
1337     * to initialize, load state, etc */
1338    if (cheat->rumble_initialized > 300)
1339    {
1340       if (rumble)
1341       {
1342          cheat->rumble_primary_end_time   = current_time + (cheat->rumble_primary_duration * 1000);
1343          cheat->rumble_secondary_end_time = current_time + (cheat->rumble_secondary_duration * 1000);
1344          input_driver_set_rumble_state(cheat->rumble_port, RETRO_RUMBLE_STRONG, cheat->rumble_primary_strength);
1345          input_driver_set_rumble_state(cheat->rumble_port, RETRO_RUMBLE_WEAK, cheat->rumble_secondary_strength);
1346       }
1347    }
1348    else
1349    {
1350       cheat->rumble_initialized++;
1351       return;
1352    }
1353 
1354    if (cheat->rumble_primary_end_time <= current_time)
1355    {
1356       if (cheat->rumble_primary_end_time != 0)
1357          input_driver_set_rumble_state(cheat->rumble_port,
1358                RETRO_RUMBLE_STRONG, 0);
1359       cheat->rumble_primary_end_time = 0;
1360    }
1361    else
1362    {
1363       input_driver_set_rumble_state(cheat->rumble_port,
1364             RETRO_RUMBLE_STRONG, cheat->rumble_primary_strength);
1365    }
1366 
1367    if (cheat->rumble_secondary_end_time <= current_time)
1368    {
1369       if (cheat->rumble_secondary_end_time != 0)
1370          input_driver_set_rumble_state(cheat->rumble_port, RETRO_RUMBLE_WEAK, 0);
1371       cheat->rumble_secondary_end_time = 0;
1372    }
1373    else
1374       input_driver_set_rumble_state(cheat->rumble_port, RETRO_RUMBLE_WEAK, cheat->rumble_secondary_strength);
1375 }
1376 
cheat_manager_apply_retro_cheats(void)1377 void cheat_manager_apply_retro_cheats(void)
1378 {
1379    unsigned i;
1380    unsigned int offset;
1381    unsigned int mask           = 0;
1382    unsigned int bytes_per_item = 1;
1383    unsigned int bits           = 8;
1384    unsigned int curr_val       = 0;
1385    bool run_cheat              = true;
1386 #ifdef HAVE_CHEEVOS
1387    bool cheat_applied          = false;
1388 #endif
1389    cheat_manager_t   *cheat_st = &cheat_manager_state;
1390 
1391    if ((!cheat_st->cheats))
1392       return;
1393 
1394    for (i = 0; i < cheat_st->size; i++)
1395    {
1396       unsigned char *curr       = NULL;
1397       bool set_value            = false;
1398       unsigned int idx          = 0;
1399       unsigned int value_to_set = 0;
1400       unsigned int repeat_iter  = 0;
1401       unsigned int address_mask = cheat_st->cheats[i].address_mask;
1402 
1403       if (cheat_st->cheats[i].handler != CHEAT_HANDLER_TYPE_RETRO || !cheat_st->cheats[i].state)
1404          continue;
1405       if (!cheat_st->memory_initialized)
1406          cheat_manager_initialize_memory(NULL, 0, false);
1407 
1408       /* If we're still not initialized, something
1409        * must have gone wrong - just bail */
1410       if (!cheat_st->memory_initialized)
1411          return;
1412 
1413       if (!run_cheat)
1414       {
1415          run_cheat = true;
1416          continue;
1417       }
1418       cheat_manager_setup_search_meta(cheat_st->cheats[i].memory_search_size, &bytes_per_item, &mask, &bits);
1419 
1420       curr   = cheat_st->curr_memory_buf;
1421       idx    = cheat_st->cheats[i].address;
1422 
1423       offset = translate_address(idx, &curr);
1424 
1425       switch (bytes_per_item)
1426       {
1427          case 2:
1428             curr_val = cheat_st->big_endian ?
1429                (*(curr + idx - offset) * 256) + *(curr + idx + 1 - offset) :
1430                *(curr + idx - offset) + (*(curr + idx + 1 - offset) * 256);
1431             break;
1432          case 4:
1433             curr_val = cheat_st->big_endian ?
1434                (*(curr + idx - offset) * 256 * 256 * 256) + (*(curr + idx + 1 - offset) * 256 * 256) + (*(curr + idx + 2 - offset) * 256) + *(curr + idx + 3 - offset) :
1435                *(curr + idx - offset) + (*(curr + idx + 1 - offset) * 256) + (*(curr + idx + 2 - offset) * 256 * 256) + (*(curr + idx + 3 - offset) * 256 * 256 * 256);
1436             break;
1437          case 1:
1438          default:
1439             curr_val = *(curr + idx - offset);
1440             break;
1441       }
1442 
1443       cheat_manager_apply_rumble(&cheat_st->cheats[i], curr_val);
1444 
1445       switch (cheat_st->cheats[i].cheat_type)
1446       {
1447          case CHEAT_TYPE_SET_TO_VALUE:
1448             set_value = true;
1449             value_to_set = cheat_st->cheats[i].value;
1450             break;
1451          case CHEAT_TYPE_INCREASE_VALUE:
1452             set_value = true;
1453             value_to_set = curr_val + cheat_st->cheats[i].value;
1454             break;
1455          case CHEAT_TYPE_DECREASE_VALUE:
1456             set_value = true;
1457             value_to_set = curr_val - cheat_st->cheats[i].value;
1458             break;
1459          case CHEAT_TYPE_RUN_NEXT_IF_EQ:
1460             if (!(curr_val == cheat_st->cheats[i].value))
1461                run_cheat = false;
1462             break;
1463          case CHEAT_TYPE_RUN_NEXT_IF_NEQ:
1464             if (!(curr_val != cheat_st->cheats[i].value))
1465                run_cheat = false;
1466             break;
1467          case CHEAT_TYPE_RUN_NEXT_IF_LT:
1468             if (!(cheat_st->cheats[i].value < curr_val))
1469                run_cheat = false;
1470             break;
1471          case CHEAT_TYPE_RUN_NEXT_IF_GT:
1472             if (!(cheat_st->cheats[i].value > curr_val))
1473                run_cheat = false;
1474             break;
1475       }
1476 
1477       if (set_value)
1478       {
1479 #ifdef HAVE_CHEEVOS
1480          cheat_applied = true;
1481 #endif
1482          for (repeat_iter = 1; repeat_iter <= cheat_st->cheats[i].repeat_count; repeat_iter++)
1483          {
1484             switch (bytes_per_item)
1485             {
1486                case 2:
1487                   if (cheat_st->cheats[i].big_endian)
1488                   {
1489                      *(curr + idx - offset) = (value_to_set >> 8) & 0xFF;
1490                      *(curr + idx + 1 - offset) = value_to_set & 0xFF;
1491                   }
1492                   else
1493                   {
1494                      *(curr + idx - offset) = value_to_set & 0xFF;
1495                      *(curr + idx + 1 - offset) = (value_to_set >> 8) & 0xFF;
1496                   }
1497                   break;
1498                case 4:
1499                   if (cheat_st->cheats[i].big_endian)
1500                   {
1501                      *(curr + idx - offset) = (value_to_set >> 24) & 0xFF;
1502                      *(curr + idx + 1 - offset) = (value_to_set >> 16) & 0xFF;
1503                      *(curr + idx + 2 - offset) = (value_to_set >> 8) & 0xFF;
1504                      *(curr + idx + 3 - offset) = value_to_set & 0xFF;
1505                   }
1506                   else
1507                   {
1508                      *(curr + idx - offset) = value_to_set & 0xFF;
1509                      *(curr + idx + 1 - offset) = (value_to_set >> 8) & 0xFF;
1510                      *(curr + idx + 2 - offset) = (value_to_set >> 16) & 0xFF;
1511                      *(curr + idx + 3 - offset) = (value_to_set >> 24) & 0xFF;
1512                   }
1513                   break;
1514                case 1:
1515                   if (bits < 8)
1516                   {
1517                      unsigned bitpos;
1518                      unsigned char val = *(curr + idx - offset);
1519 
1520                      for (bitpos = 0; bitpos < 8; bitpos++)
1521                      {
1522                         if ((address_mask >> bitpos) & 0x01)
1523                         {
1524                            mask = (~(1 << bitpos) & 0xFF);
1525                            /* Clear current bit value */
1526                            val = val & mask;
1527                            /* Inject cheat bit value */
1528                            val = val | (((value_to_set >> bitpos) & 0x01) << bitpos);
1529                         }
1530                      }
1531 
1532                      *(curr + idx - offset) = val;
1533                   }
1534                   else
1535                      *(curr + idx - offset) = value_to_set & 0xFF;
1536                   break;
1537                default:
1538                   *(curr + idx - offset) = value_to_set & 0xFF;
1539                   break;
1540             }
1541 
1542             value_to_set += cheat_st->cheats[i].repeat_add_to_value;
1543 
1544             if (mask != 0)
1545                value_to_set = value_to_set % mask;
1546 
1547             if (bits < 8)
1548             {
1549                unsigned int bit_iter;
1550                for (bit_iter = 0; bit_iter < cheat_st->cheats[i].repeat_add_to_address; bit_iter++)
1551                {
1552                   address_mask = (address_mask << mask) & 0xFF;
1553 
1554                   if (address_mask == 0)
1555                   {
1556                      address_mask = mask;
1557                      idx++;
1558                   }
1559                }
1560             }
1561             else
1562                idx += (cheat_st->cheats[i].repeat_add_to_address * bytes_per_item);
1563 
1564             idx = idx % cheat_st->total_memory_size;
1565 
1566             offset = translate_address(idx, &curr);
1567          }
1568       }
1569    }
1570 
1571 #ifdef HAVE_CHEEVOS
1572    if (cheat_applied && rcheevos_hardcore_active())
1573       cheat_manager_pause_cheevos();
1574 #endif
1575 }
1576 
cheat_manager_match_action(enum cheat_match_action_type match_action,unsigned int target_match_idx,unsigned int * address,unsigned int * address_mask,unsigned int * prev_value,unsigned int * curr_value)1577 void cheat_manager_match_action(enum cheat_match_action_type match_action, unsigned int target_match_idx, unsigned int *address, unsigned int *address_mask,
1578       unsigned int *prev_value, unsigned int *curr_value)
1579 {
1580    unsigned int byte_part;
1581    unsigned int idx;
1582    unsigned int start_idx;
1583    unsigned int           mask = 0;
1584    unsigned int bytes_per_item = 1;
1585    unsigned int           bits = 8;
1586    unsigned int       curr_val = 0;
1587    unsigned int       prev_val = 0;
1588    unsigned int         offset = 0;
1589    cheat_manager_t   *cheat_st = &cheat_manager_state;
1590    unsigned char         *curr = cheat_st->curr_memory_buf;
1591    unsigned char         *prev = cheat_st->prev_memory_buf;
1592    unsigned int curr_match_idx = 0;
1593 
1594    if (target_match_idx > cheat_st->num_matches - 1)
1595       return;
1596 
1597    if (cheat_st->num_memory_buffers == 0)
1598       return;
1599 
1600    cheat_manager_setup_search_meta(cheat_st->search_bit_size, &bytes_per_item, &mask, &bits);
1601 
1602    if (match_action == CHEAT_MATCH_ACTION_TYPE_BROWSE)
1603       start_idx = *address;
1604    else
1605       start_idx = 0;
1606 
1607    for (idx = start_idx; idx < cheat_st->total_memory_size; idx = idx + bytes_per_item)
1608    {
1609       offset = translate_address(idx, &curr);
1610 
1611       switch (bytes_per_item)
1612       {
1613       case 2:
1614          curr_val = cheat_st->big_endian ?
1615                (*(curr + idx - offset) * 256) + *(curr + idx + 1 - offset) :
1616                *(curr + idx - offset) + (*(curr + idx + 1 - offset) * 256);
1617          if (prev)
1618             prev_val = cheat_st->big_endian ?
1619                   (*(prev + idx) * 256) + *(prev + idx + 1) :
1620                   *(prev + idx) + (*(prev + idx + 1) * 256);
1621          break;
1622       case 4:
1623          curr_val = cheat_st->big_endian ?
1624                (*(curr + idx - offset) * 256 * 256 * 256) + (*(curr + idx + 1 - offset) * 256 * 256) + (*(curr + idx + 2 - offset) * 256) + *(curr + idx + 3 - offset) :
1625                *(curr + idx - offset) + (*(curr + idx + 1 - offset) * 256) + (*(curr + idx + 2 - offset) * 256 * 256) + (*(curr + idx + 3 - offset) * 256 * 256 * 256);
1626          if (prev)
1627             prev_val = cheat_st->big_endian ?
1628                   (*(prev + idx) * 256 * 256 * 256) + (*(prev + idx + 1) * 256 * 256) + (*(prev + idx + 2) * 256) + *(prev + idx + 3) :
1629                   *(prev + idx) + (*(prev + idx + 1) * 256) + (*(prev + idx + 2) * 256 * 256) + (*(prev + idx + 3) * 256 * 256 * 256);
1630          break;
1631       case 1:
1632       default:
1633          curr_val = *(curr + idx - offset);
1634          if (prev)
1635             prev_val = *(prev + idx);
1636          break;
1637       }
1638 
1639       if (match_action == CHEAT_MATCH_ACTION_TYPE_BROWSE)
1640       {
1641          *curr_value = curr_val;
1642          *prev_value = prev_val;
1643          return;
1644       }
1645 
1646       if (!prev)
1647          return;
1648 
1649       for (byte_part = 0; byte_part < 8 / bits; byte_part++)
1650       {
1651          unsigned int prev_match;
1652 
1653          if (bits < 8)
1654          {
1655             prev_match = *(cheat_st->matches + idx) & (mask << (byte_part * bits));
1656             if (prev_match)
1657             {
1658                if (target_match_idx == curr_match_idx)
1659                {
1660                   switch (match_action)
1661                   {
1662                   case CHEAT_MATCH_ACTION_TYPE_BROWSE:
1663                      return;
1664                   case CHEAT_MATCH_ACTION_TYPE_VIEW:
1665                      *address = idx;
1666                      *address_mask = (mask << (byte_part * bits));
1667                      *curr_value = curr_val;
1668                      *prev_value = prev_val;
1669                      return;
1670                   case CHEAT_MATCH_ACTION_TYPE_COPY:
1671                      if (!cheat_manager_add_new_code(cheat_st->search_bit_size, idx, (mask << (byte_part * bits)),
1672                            cheat_st->big_endian, curr_val))
1673                         runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADD_MATCH_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1674                      else
1675                         runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1676                      return;
1677                   case CHEAT_MATCH_ACTION_TYPE_DELETE:
1678                      if (bits < 8)
1679                         *(cheat_st->matches + idx) = *(cheat_st->matches + idx) &
1680                               ((~(mask << (byte_part * bits))) & 0xFF);
1681                      else
1682                         memset(cheat_st->matches + idx, 0, bytes_per_item);
1683                      if (cheat_st->num_matches > 0)
1684                         cheat_st->num_matches--;
1685                      runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1686                      return;
1687                   }
1688                   return;
1689                }
1690                curr_match_idx++;
1691             }
1692          }
1693          else
1694          {
1695             prev_match = *(cheat_st->matches + idx);
1696             if (prev_match)
1697             {
1698                if (target_match_idx == curr_match_idx)
1699                {
1700                   switch (match_action)
1701                   {
1702                   case CHEAT_MATCH_ACTION_TYPE_BROWSE:
1703                      return;
1704                   case CHEAT_MATCH_ACTION_TYPE_VIEW:
1705                      *address = idx;
1706                      *address_mask = 0xFF;
1707                      *curr_value = curr_val;
1708                      *prev_value = prev_val;
1709                      return;
1710                   case CHEAT_MATCH_ACTION_TYPE_COPY:
1711                      if (!cheat_manager_add_new_code(cheat_st->search_bit_size, idx, 0xFF,
1712                            cheat_st->big_endian, curr_val))
1713                         runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADD_MATCH_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1714                      else
1715                         runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADD_MATCH_SUCCESS), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1716                      return;
1717                   case CHEAT_MATCH_ACTION_TYPE_DELETE:
1718                      if (bits < 8)
1719                         *(cheat_st->matches + idx) = *(cheat_st->matches + idx) &
1720                               ((~(mask << (byte_part * bits))) & 0xFF);
1721                      else
1722                         memset(cheat_st->matches + idx, 0, bytes_per_item);
1723                      if (cheat_st->num_matches > 0)
1724                         cheat_st->num_matches--;
1725                      runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_DELETE_MATCH_SUCCESS), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1726                      return;
1727                   }
1728                }
1729 
1730                curr_match_idx++;
1731             }
1732          }
1733       }
1734    }
1735 }
1736 
cheat_manager_copy_match(rarch_setting_t * setting,size_t idx,bool wraparound)1737 int cheat_manager_copy_match(rarch_setting_t *setting, size_t idx, bool wraparound)
1738 {
1739    cheat_manager_t *cheat_st = &cheat_manager_state;
1740    cheat_manager_match_action(CHEAT_MATCH_ACTION_TYPE_COPY,
1741          cheat_st->match_idx, NULL, NULL, NULL, NULL);
1742    return 0;
1743 }
1744 
cheat_manager_delete_match(rarch_setting_t * setting,size_t idx,bool wraparound)1745 int cheat_manager_delete_match(rarch_setting_t *setting, size_t idx, bool wraparound)
1746 {
1747    bool              refresh = false;
1748    cheat_manager_t *cheat_st = &cheat_manager_state;
1749 
1750    cheat_manager_match_action(CHEAT_MATCH_ACTION_TYPE_DELETE,
1751          cheat_st->match_idx, NULL, NULL, NULL, NULL);
1752 #ifdef HAVE_MENU
1753    menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
1754    menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
1755 #endif
1756    return 0;
1757 }
1758