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