1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2011-2017 - Daniel De Matteis
3 * Copyright (C) 2016-2019 - Brad Parker
4 * Copyright (C) 2016-2019 - Andrés Suárez
5 *
6 * RetroArch is free software: you can redistribute it and/or modify it under the terms
7 * of the GNU General Public License as published by the Free Software Found-
8 * ation, either version 3 of the License, or (at your option) any later version.
9 *
10 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 * PURPOSE. See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with RetroArch.
15 * If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /* TODO/FIXME - turn this into actual task */
19
20 #include <stdio.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <string.h>
25 #include <time.h>
26 #include <errno.h>
27
28 #ifdef _WIN32
29 #ifdef _XBOX
30 #include <xtl.h>
31 #define setmode _setmode
32 #define INVALID_FILE_ATTRIBUTES -1
33 #else
34 #include <io.h>
35 #include <fcntl.h>
36 #include <windows.h>
37 #endif
38 #endif
39
40 #ifdef __WINRT__
41 #include <uwp/uwp_func.h>
42 #endif
43
44 #ifdef HAVE_CONFIG_H
45 #include "../config.h"
46 #endif
47
48 #include <boolean.h>
49
50 #include <encodings/crc32.h>
51 #include <compat/strl.h>
52 #include <compat/posix_string.h>
53 #include <file/file_path.h>
54 #include <file/archive_file.h>
55 #include <streams/file_stream.h>
56 #include <string/stdstring.h>
57 #include <lists/string_list.h>
58 #include <lists/dir_list.h>
59 #include <vfs/vfs_implementation.h>
60 #include <array/rbuf.h>
61
62 #include <retro_miscellaneous.h>
63 #include <retro_assert.h>
64
65 #ifdef HAVE_MENU
66 #include "../menu/menu_driver.h"
67 #endif
68
69 #ifdef HAVE_GFX_WIDGETS
70 #include "../gfx/gfx_widgets.h"
71 #endif
72
73 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
74 #include "../menu/menu_shader.h"
75 #endif
76
77 #ifdef HAVE_CHEEVOS
78 #include "../cheevos/cheevos.h"
79 #endif
80
81 #include "task_content.h"
82 #include "tasks_internal.h"
83
84 #include "../command.h"
85 #include "../core_info.h"
86 #include "../content.h"
87 #include "../configuration.h"
88 #include "../defaults.h"
89 #include "../frontend/frontend.h"
90 #include "../playlist.h"
91 #include "../paths.h"
92 #include "../retroarch.h"
93 #include "../verbosity.h"
94
95 #include "../msg_hash.h"
96 #include "../content.h"
97 #include "../dynamic.h"
98 #include "../retroarch.h"
99 #include "../file_path_special.h"
100 #include "../core.h"
101 #include "../paths.h"
102 #include "../verbosity.h"
103
104 #ifdef HAVE_DISCORD
105 #include "../network/discord.h"
106
107 /* TODO/FIXME - get rid of this public global */
108 extern bool discord_is_inited;
109 #endif
110
111 #define MAX_ARGS 32
112
113 typedef struct content_stream content_stream_t;
114 typedef struct content_information_ctx content_information_ctx_t;
115
116 struct content_stream
117 {
118 const uint8_t *b;
119 size_t c;
120 uint32_t a;
121 uint32_t crc;
122 };
123
124 struct content_information_ctx
125 {
126 char *name_ips;
127 char *name_bps;
128 char *name_ups;
129
130 char *valid_extensions;
131 char *directory_cache;
132 char *directory_system;
133
134 struct
135 {
136 struct retro_subsystem_info *data;
137 unsigned size;
138 } subsystem;
139
140 bool block_extract;
141 bool need_fullpath;
142 bool set_supports_no_game_enable;
143 #ifdef HAVE_PATCH
144 bool is_ips_pref;
145 bool is_bps_pref;
146 bool is_ups_pref;
147 bool patch_is_blocked;
148 #endif
149 bool bios_is_missing;
150 bool check_firmware_before_loading;
151 };
152
153 /*************************************/
154 /* Content file info functions START */
155 /*************************************/
156
content_file_override_free(content_state_t * p_content)157 static void content_file_override_free(
158 content_state_t *p_content)
159 {
160 size_t i;
161
162 if (!p_content->content_override_list)
163 return;
164
165 for (i = 0; i < RBUF_LEN(p_content->content_override_list); i++)
166 {
167 content_file_override_t *override =
168 &p_content->content_override_list[i];
169
170 if (!override || !override->ext)
171 continue;
172
173 free(override->ext);
174 }
175
176 RBUF_FREE(p_content->content_override_list);
177 }
178
179 /* Returns true if an override for content files
180 * of extension 'ext' has been set */
content_file_override_get_ext(content_state_t * p_content,const char * ext,const content_file_override_t ** override)181 static bool content_file_override_get_ext(
182 content_state_t *p_content,
183 const char *ext,
184 const content_file_override_t **override)
185 {
186 size_t num_overrides;
187 size_t i;
188
189 if (!p_content || string_is_empty(ext))
190 return false;
191
192 num_overrides = RBUF_LEN(p_content->content_override_list);
193
194 if (num_overrides < 1)
195 return false;
196
197 for (i = 0; i < num_overrides; i++)
198 {
199 content_file_override_t *content_override =
200 &p_content->content_override_list[i];
201
202 if (!content_override ||
203 !content_override->ext)
204 continue;
205
206 if (string_is_equal_noncase(
207 content_override->ext, ext))
208 {
209 if (override)
210 *override = content_override;
211
212 return true;
213 }
214 }
215
216 return false;
217 }
218
content_file_override_set(const struct retro_system_content_info_override * overrides)219 bool content_file_override_set(
220 const struct retro_system_content_info_override *overrides)
221 {
222 content_state_t *p_content = content_state_get_ptr();
223 size_t i;
224
225 if (!p_content || !overrides)
226 return false;
227
228 /* Free any existing override list */
229 content_file_override_free(p_content);
230
231 for (i = 0; overrides[i].extensions; i++)
232 {
233 struct string_list ext_list = {0};
234 size_t j;
235
236 /* Get list of extensions affected by override */
237 string_list_initialize(&ext_list);
238 if (!string_split_noalloc(&ext_list,
239 overrides[i].extensions, "|"))
240 {
241 string_list_deinitialize(&ext_list);
242 continue;
243 }
244
245 for (j = 0; j < ext_list.size; j++)
246 {
247 const char *ext = ext_list.elems[j].data;
248 content_file_override_t *override = NULL;
249 size_t num_entries;
250
251 /* Check whether extension has already been
252 * registered */
253 if (string_is_empty(ext) ||
254 content_file_override_get_ext(p_content, ext, NULL))
255 continue;
256
257 /* Add current override to the list */
258 num_entries = RBUF_LEN(p_content->content_override_list);
259
260 if (!RBUF_TRYFIT(p_content->content_override_list,
261 num_entries + 1))
262 {
263 string_list_deinitialize(&ext_list);
264 return false;
265 }
266
267 RBUF_RESIZE(p_content->content_override_list,
268 num_entries + 1);
269
270 RARCH_LOG("[CONTENT OVERRIDE]: File Extension: '%s' - need_fullpath: %s, persistent_data: %s\n",
271 ext, overrides[i].need_fullpath ? "TRUE" : "FALSE",
272 overrides[i].persistent_data ? "TRUE" : "FALSE");
273
274 override = &p_content->content_override_list[num_entries];
275 override->ext = strdup(ext);
276 override->need_fullpath = overrides[i].need_fullpath;
277 override->persistent_data = overrides[i].persistent_data;
278 }
279
280 string_list_deinitialize(&ext_list);
281 }
282
283 return true;
284 }
285
286 /* Frees any content data that is not flagged
287 * as 'persistent'. Should be called after
288 * content_file_load() */
content_file_list_free_transient_data(content_file_list_t * file_list)289 static void content_file_list_free_transient_data(
290 content_file_list_t *file_list)
291 {
292 size_t i;
293
294 if (!file_list)
295 return;
296
297 for (i = 0; i < file_list->size; i++)
298 {
299 content_file_info_t *file_info = &file_list->entries[i];
300
301 if (file_info->data &&
302 !file_info->persistent_data)
303 {
304 free((void*)file_info->data);
305
306 file_info->data = NULL;
307 file_info->data_size = 0;
308 }
309 }
310 }
311
content_file_list_free_entry(content_file_info_t * file_info)312 static void content_file_list_free_entry(
313 content_file_info_t *file_info)
314 {
315 if (!file_info)
316 return;
317
318 if (file_info->full_path)
319 {
320 free(file_info->full_path);
321 file_info->full_path = NULL;
322 }
323
324 if (file_info->archive_path)
325 {
326 free(file_info->archive_path);
327 file_info->archive_path = NULL;
328 }
329
330 if (file_info->archive_file)
331 {
332 free(file_info->archive_file);
333 file_info->archive_file = NULL;
334 }
335
336 if (file_info->dir)
337 {
338 free(file_info->dir);
339 file_info->dir = NULL;
340 }
341
342 if (file_info->name)
343 {
344 free(file_info->name);
345 file_info->name = NULL;
346 }
347
348 if (file_info->ext)
349 {
350 free(file_info->ext);
351 file_info->ext = NULL;
352 }
353
354 if (file_info->meta)
355 {
356 free(file_info->meta);
357 file_info->meta = NULL;
358 }
359
360 if (file_info->data)
361 {
362 free((void*)file_info->data);
363 file_info->data = NULL;
364 }
365 file_info->data_size = 0;
366
367 file_info->file_in_archive = false;
368 file_info->persistent_data = false;
369 }
370
content_file_list_free(content_file_list_t * file_list)371 static void content_file_list_free(
372 content_file_list_t *file_list)
373 {
374 if (!file_list)
375 return;
376
377 if (file_list->entries)
378 {
379 size_t i;
380
381 for (i = 0; i < file_list->size; i++)
382 {
383 content_file_info_t *file_info = &file_list->entries[i];
384 content_file_list_free_entry(file_info);
385 }
386
387 free(file_list->entries);
388 }
389
390 if (file_list->temporary_files)
391 {
392 size_t i;
393
394 /* Remove any temporary content files from
395 * the file system */
396 for (i = 0; i < file_list->temporary_files->size; i++)
397 {
398 const char *path = file_list->temporary_files->elems[i].data;
399
400 if (string_is_empty(path))
401 continue;
402
403 RARCH_LOG("[CONTENT LOAD]: %s: %s\n",
404 msg_hash_to_str(MSG_REMOVING_TEMPORARY_CONTENT_FILE),
405 path);
406
407 if (filestream_delete(path) != 0)
408 RARCH_ERR("[CONTENT LOAD]: %s: %s.\n",
409 msg_hash_to_str(MSG_FAILED_TO_REMOVE_TEMPORARY_FILE),
410 path);
411 }
412
413 string_list_free(file_list->temporary_files);
414 }
415
416 if (file_list->game_info)
417 free(file_list->game_info);
418
419 if (file_list->game_info_ext)
420 free(file_list->game_info_ext);
421
422 free(file_list);
423 }
424
content_file_list_init(size_t size)425 static content_file_list_t *content_file_list_init(size_t size)
426 {
427 content_file_list_t *file_list = NULL;
428
429 if (size < 1)
430 goto error;
431
432 file_list = (content_file_list_t *)malloc(sizeof(*file_list));
433 if (!file_list)
434 goto error;
435
436 /* Set initial 'values' */
437 file_list->entries = NULL;
438 file_list->size = 0;
439 file_list->temporary_files = string_list_new();
440 file_list->game_info = NULL;
441 file_list->game_info_ext = NULL;
442
443 if (!file_list->temporary_files)
444 goto error;
445
446 /* Create entries list */
447 file_list->entries = (content_file_info_t *)
448 calloc(size, sizeof(content_file_info_t));
449 if (!file_list->entries)
450 goto error;
451
452 file_list->size = size;
453
454 /* Create retro_game_info object */
455 file_list->game_info = (struct retro_game_info *)
456 calloc(size, sizeof(struct retro_game_info));
457 if (!file_list->game_info)
458 goto error;
459
460 /* Create retro_game_info_ext object */
461 file_list->game_info_ext = (struct retro_game_info_ext *)
462 calloc(size, sizeof(struct retro_game_info_ext));
463 if (!file_list->game_info_ext)
464 goto error;
465
466 return file_list;
467
468 error:
469 if (file_list)
470 content_file_list_free(file_list);
471 return NULL;
472 }
473
474 /* Convenience function: Adds an entry to the
475 * temporary (i.e. extracted) content file list.
476 * Returns pointer to allocated char array. */
content_file_list_append_temporary(content_file_list_t * file_list,const char * path)477 static const char *content_file_list_append_temporary(
478 content_file_list_t *file_list,
479 const char *path)
480 {
481 union string_list_elem_attr attr;
482
483 if (!file_list ||
484 string_is_empty(path))
485 return NULL;
486
487 attr.i = 0;
488
489 if (string_list_append(file_list->temporary_files,
490 path, attr))
491 return file_list->temporary_files->elems[
492 file_list->temporary_files->size - 1].data;
493
494 return NULL;
495 }
496
497 /* Note: Takes ownership of supplied 'data' buffer */
content_file_list_set_info(content_file_list_t * file_list,const char * path,void * data,size_t data_size,bool persistent_data,size_t idx)498 static bool content_file_list_set_info(
499 content_file_list_t *file_list,
500 const char *path,
501 void *data,
502 size_t data_size,
503 bool persistent_data,
504 size_t idx)
505 {
506 content_file_info_t *file_info = NULL;
507 struct retro_game_info *game_info = NULL;
508 struct retro_game_info_ext *game_info_ext = NULL;
509
510 if (!file_list ||
511 (idx >= file_list->size))
512 return false;
513
514 file_info = &file_list->entries[idx];
515 if (!file_info)
516 return false;
517
518 game_info = &file_list->game_info[idx];
519 if (!game_info)
520 return false;
521
522 game_info_ext = &file_list->game_info_ext[idx];
523 if (!game_info_ext)
524 return false;
525
526 /* Clear any existing info */
527 content_file_list_free_entry(file_info);
528
529 game_info->path = NULL;
530 game_info->data = NULL;
531 game_info->size = 0;
532 game_info->meta = NULL;
533
534 game_info_ext->full_path = NULL;
535 game_info_ext->archive_path = NULL;
536 game_info_ext->archive_file = NULL;
537 game_info_ext->dir = NULL;
538 game_info_ext->name = NULL;
539 game_info_ext->ext = NULL;
540 game_info_ext->meta = NULL;
541 game_info_ext->data = NULL;
542 game_info_ext->size = 0;
543 game_info_ext->file_in_archive = false;
544 game_info_ext->persistent_data = false;
545
546 /* Assign data */
547 if (( data && !data_size) ||
548 (!data && data_size))
549 return false;
550
551 file_info->data = data;
552 file_info->data_size = data_size;
553 file_info->persistent_data = persistent_data;
554
555 /* Assign paths
556 * > There is some degree of redundant data
557 * here, but we need it in this format
558 * (persistent copies of each parameter)
559 * to minimise complications when passing
560 * extended path info to cores */
561 if (!string_is_empty(path))
562 {
563 const char *archive_delim = NULL;
564 const char *ext = NULL;
565 char dir[PATH_MAX_LENGTH];
566 char name[256];
567
568 dir[0] = '\0';
569 name[0] = '\0';
570
571 /* 'Full' path - may point to a file
572 * inside an archive */
573 file_info->full_path = strdup(path);
574
575 /* File extension - may be used core-side
576 * to differentiate content types */
577 ext = path_get_extension(path);
578 if (ext)
579 {
580 file_info->ext = strdup(ext);
581 /* File extension is always presented
582 * core-side in lowercase format */
583 string_to_lower(file_info->ext);
584 }
585
586 /* Check whether path corresponds to a file
587 * inside an archive */
588 archive_delim = path_get_archive_delim(path);
589
590 if (archive_delim)
591 {
592 char archive_path[PATH_MAX_LENGTH];
593 size_t len;
594
595 archive_path[0] = '\0';
596
597 /* Extract path of parent archive */
598 len = (size_t)(1 + archive_delim - path);
599 len = (len < PATH_MAX_LENGTH) ? len : PATH_MAX_LENGTH;
600
601 strlcpy(archive_path, path, len * sizeof(char));
602 if (!string_is_empty(archive_path))
603 file_info->archive_path = strdup(archive_path);
604
605 /* Extract name of file in archive */
606 archive_delim++;
607 if (!string_is_empty(archive_delim))
608 file_info->archive_file = strdup(archive_delim);
609
610 /* Extract parent directory - may be used
611 * core-side as a reference point for searching
612 * related content (e.g. same file name, different
613 * extension) */
614 fill_pathname_parent_dir(dir, archive_path, sizeof(dir));
615
616 /* Extract 'canonical' name/id of content file -
617 * may be used core-side as a reference point for
618 * searching related content. For archived content,
619 * this is the basename of the archive file without
620 * extension */
621 fill_pathname_base_noext(name, archive_path, sizeof(name));
622
623 file_info->file_in_archive = true;
624 }
625 else
626 {
627 /* If path corresponds to a 'normal' file,
628 * just extract parent directory */
629 fill_pathname_parent_dir(dir, path, sizeof(dir));
630
631 /* For uncompressed content, 'canonical' name/id
632 * is the basename of the content file, without
633 * extension */
634 fill_pathname_base_noext(name, path, sizeof(name));
635 }
636
637 if (!string_is_empty(dir))
638 {
639 /* Remove any trailing slash */
640 char *last_slash = find_last_slash(dir);
641 if (last_slash && (last_slash[1] == '\0'))
642 *last_slash = '\0';
643
644 if (!string_is_empty(dir))
645 file_info->dir = strdup(dir);
646 }
647
648 if (!string_is_empty(name))
649 file_info->name = strdup(name);
650 }
651
652 /* Assign retro_game_info pointers */
653 game_info->path = file_info->full_path;
654 game_info->data = file_info->data;
655 game_info->size = file_info->data_size;
656 game_info->meta = file_info->meta;
657
658 /* Assign retro_game_info_ext pointers */
659 game_info_ext->full_path = file_info->full_path;
660 game_info_ext->archive_path = file_info->archive_path;
661 game_info_ext->archive_file = file_info->archive_file;
662 game_info_ext->dir = file_info->dir;
663 game_info_ext->name = file_info->name;
664 game_info_ext->ext = file_info->ext;
665 game_info_ext->meta = file_info->meta;
666 game_info_ext->data = file_info->data;
667 game_info_ext->size = file_info->data_size;
668 game_info_ext->file_in_archive = file_info->file_in_archive;
669 game_info_ext->persistent_data = file_info->persistent_data;
670
671 return true;
672 }
673
674 /***********************************/
675 /* Content file info functions END */
676 /***********************************/
677
678 /********************************/
679 /* Content file functions START */
680 /********************************/
681
682 #define CONTENT_FILE_ATTR_RESET(attr) (attr.i = 0)
683
684 #define CONTENT_FILE_ATTR_SET_BLOCK_EXTRACT(attr, block_extract) (attr.i |= ((block_extract) ? 1 : 0))
685 #define CONTENT_FILE_ATTR_SET_NEED_FULLPATH(attr, need_fullpath) (attr.i |= ((need_fullpath) ? 2 : 0))
686 #define CONTENT_FILE_ATTR_SET_REQUIRED(attr, required) (attr.i |= ((required) ? 4 : 0))
687 #define CONTENT_FILE_ATTR_SET_PERSISTENT(attr, persistent) (attr.i |= ((persistent) ? 8 : 0))
688
689 #define CONTENT_FILE_ATTR_GET_BLOCK_EXTRACT(attr) ((attr.i & 1) != 0)
690 #define CONTENT_FILE_ATTR_GET_NEED_FULLPATH(attr) ((attr.i & 2) != 0)
691 #define CONTENT_FILE_ATTR_GET_REQUIRED(attr) ((attr.i & 4) != 0)
692 #define CONTENT_FILE_ATTR_GET_PERSISTENT(attr) ((attr.i & 8) != 0)
693
694 /**
695 * content_file_load_into_memory:
696 * @content_path : path of the content file.
697 * @data : buffer into which the content file will be read.
698 * @data_size : size of the resultant content buffer.
699 *
700 * Reads the content file into memory. Also performs soft patching
701 * (see patch_content function) if soft patching has not been
702 * blocked by the user.
703 *
704 * Returns: true if successful, false on error.
705 **/
content_file_load_into_memory(content_information_ctx_t * content_ctx,content_state_t * p_content,const char * content_path,bool content_compressed,size_t idx,enum rarch_content_type first_content_type,uint8_t ** data,size_t * data_size)706 static bool content_file_load_into_memory(
707 content_information_ctx_t *content_ctx,
708 content_state_t *p_content,
709 const char *content_path,
710 bool content_compressed,
711 size_t idx,
712 enum rarch_content_type first_content_type,
713 uint8_t **data,
714 size_t *data_size)
715 {
716 uint8_t *content_data = NULL;
717 int64_t content_size = 0;
718
719 *data = NULL;
720 *data_size = 0;
721
722 RARCH_LOG("[CONTENT LOAD]: %s: %s\n",
723 msg_hash_to_str(MSG_LOADING_CONTENT_FILE), content_path);
724
725 /* Read content from file into memory buffer */
726 #ifdef HAVE_COMPRESSION
727 if (content_compressed)
728 {
729 if (!file_archive_compressed_read(content_path,
730 (void**)&content_data, NULL, &content_size))
731 return false;
732 }
733 else
734 #endif
735 if (!filestream_read_file(content_path,
736 (void**)&content_data, &content_size))
737 return false;
738
739 if (content_size < 0)
740 return false;
741
742 /* First content file is significant: attempt to do
743 * soft patching, CRC checking, etc. */
744 if (idx == 0)
745 {
746 /* If we have a media type, ignore patches/CRC32
747 * calculation. */
748 if (first_content_type == RARCH_CONTENT_NONE)
749 {
750 bool has_patch = false;
751
752 #ifdef HAVE_PATCH
753 /* Attempt to apply a patch. */
754 if (!content_ctx->patch_is_blocked)
755 has_patch = patch_content(
756 content_ctx->is_ips_pref,
757 content_ctx->is_bps_pref,
758 content_ctx->is_ups_pref,
759 content_ctx->name_ips,
760 content_ctx->name_bps,
761 content_ctx->name_ups,
762 (uint8_t**)&content_data,
763 (void*)&content_size);
764 #endif
765 /* If content is compressed or a patch has been
766 * applied, must determine CRC value using the
767 * actual data buffer, since the content path
768 * cannot be used for this purpose...
769 * In all other cases, cache the content path
770 * and defer CRC calculation until the value is
771 * actually needed */
772 if (content_compressed || has_patch)
773 {
774 p_content->rom_crc = encoding_crc32(0, content_data,
775 (size_t)content_size);
776 RARCH_LOG("[CONTENT LOAD]: CRC32: 0x%x\n",
777 (unsigned)p_content->rom_crc);
778 }
779 else
780 {
781 strlcpy(p_content->pending_rom_crc_path, content_path,
782 sizeof(p_content->pending_rom_crc_path));
783 p_content->pending_rom_crc = true;
784 }
785 }
786 else
787 p_content->rom_crc = 0;
788 }
789
790 *data = content_data;
791 *data_size = (size_t)content_size;
792
793 return true;
794 }
795
796 #ifdef HAVE_COMPRESSION
content_file_extract_from_archive(content_information_ctx_t * content_ctx,content_state_t * p_content,const char * valid_exts,const char ** content_path,char ** error_string)797 static bool content_file_extract_from_archive(
798 content_information_ctx_t *content_ctx,
799 content_state_t *p_content,
800 const char *valid_exts,
801 const char **content_path,
802 char **error_string)
803 {
804 const char *temp_path_ptr = NULL;
805 char temp_path[PATH_MAX_LENGTH];
806 char msg[1024];
807
808 temp_path[0] = '\0';
809 msg[0] = '\0';
810
811 RARCH_LOG("[CONTENT LOAD]: Core requires uncompressed content - "
812 "extracting archive to temporary directory.\n");
813
814 /* Attempt to extract file */
815 if (!file_archive_extract_file(
816 *content_path, valid_exts,
817 string_is_empty(content_ctx->directory_cache) ?
818 NULL : content_ctx->directory_cache,
819 temp_path, sizeof(temp_path)))
820 {
821 snprintf(msg, sizeof(msg), "%s: %s\n",
822 msg_hash_to_str(MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE),
823 *content_path);
824 *error_string = strdup(msg);
825 return false;
826 }
827
828 /* Add path of extracted file to temporary content
829 * list (so it can be deleted when deinitialising
830 * the core) */
831 temp_path_ptr = content_file_list_append_temporary(
832 p_content->content_list, temp_path);
833 if (!temp_path_ptr)
834 return false;
835
836 /* Update content path pointer */
837 *content_path = temp_path_ptr;
838
839 RARCH_LOG("[CONTENT LOAD]: Content successfully extracted to: %s\n",
840 temp_path);
841
842 return true;
843 }
844 #endif
845
content_file_get_path(struct string_list * content,size_t idx,const char * valid_exts,const char ** path,bool * path_is_compressed)846 static void content_file_get_path(
847 struct string_list *content,
848 size_t idx,
849 const char *valid_exts,
850 const char **path,
851 bool *path_is_compressed)
852 {
853 const char *content_path = content->elems[idx].data;
854 bool path_is_archive;
855 bool path_is_inside_archive;
856
857 *path = NULL;
858 *path_is_compressed = false;
859
860 if (string_is_empty(content_path))
861 return;
862
863 #ifdef HAVE_COMPRESSION
864 /* Check whether we are dealing with a
865 * compressed file */
866 path_is_archive = path_is_compressed_file(content_path);
867 path_is_inside_archive = path_contains_compressed_file(content_path);
868 *path_is_compressed = path_is_archive || path_is_inside_archive;
869
870 /* If extraction is permitted and content is a
871 * 'parent' archive file, must determine which
872 * internal file to load
873 * > file_archive_compressed_read() requires
874 * a 'complete' file path:
875 * <parent_archive>#<internal_file> */
876 if (!CONTENT_FILE_ATTR_GET_BLOCK_EXTRACT(content->elems[idx].attr) &&
877 path_is_archive &&
878 !path_is_inside_archive)
879 {
880 /* Get internal archive file list */
881 struct string_list *archive_list =
882 file_archive_get_file_list(content_path, valid_exts);
883
884 if (archive_list &&
885 (archive_list->size > 0))
886 {
887 const char *archive_file = NULL;
888
889 /* Ensure that list is sorted alphabetically */
890 if (archive_list->size > 1)
891 dir_list_sort(archive_list, true);
892
893 archive_file = archive_list->elems[0].data;
894
895 if (!string_is_empty(archive_file))
896 {
897 char info_path[PATH_MAX_LENGTH];
898 info_path[0] = '\n';
899
900 /* Build 'complete' archive file path */
901 snprintf(info_path, sizeof(info_path), "%s#%s",
902 content_path, archive_file);
903
904 /* Update 'content' string_list */
905 string_list_set(content, idx, info_path);
906 content_path = content->elems[idx].data;
907
908 string_list_free(archive_list);
909 }
910 }
911 }
912 #endif
913
914 *path = content_path;
915 }
916
content_file_apply_overrides(content_state_t * p_content,struct string_list * content,size_t idx,const char * path)917 static void content_file_apply_overrides(
918 content_state_t *p_content,
919 struct string_list *content,
920 size_t idx,
921 const char *path)
922 {
923 const content_file_override_t *override = NULL;
924
925 if (!p_content->content_override_list)
926 return;
927
928 /* Check whether an override has been set
929 * for files of this type */
930 if (content_file_override_get_ext(p_content,
931 path_get_extension(path), &override))
932 {
933 /* Get existing attributes */
934 bool block_extract = CONTENT_FILE_ATTR_GET_BLOCK_EXTRACT(content->elems[idx].attr);
935 bool required = CONTENT_FILE_ATTR_GET_REQUIRED(content->elems[idx].attr);
936 bool persistent = CONTENT_FILE_ATTR_GET_PERSISTENT(content->elems[idx].attr);
937
938 CONTENT_FILE_ATTR_RESET(content->elems[idx].attr);
939
940 /* Apply updates
941 * > Note that 'persistent' attribute must not
942 * be set false by an override if it is already
943 * true (frontend may require persistence for
944 * other purposes, e.g. runahead) */
945 CONTENT_FILE_ATTR_SET_BLOCK_EXTRACT(content->elems[idx].attr,
946 block_extract);
947 CONTENT_FILE_ATTR_SET_NEED_FULLPATH(content->elems[idx].attr,
948 override->need_fullpath);
949 CONTENT_FILE_ATTR_SET_REQUIRED(content->elems[idx].attr,
950 required);
951 CONTENT_FILE_ATTR_SET_PERSISTENT(content->elems[idx].attr,
952 (persistent || override->persistent_data));
953 }
954 }
955
956 /**
957 * content_file_load:
958 * @special : subsystem of content to be loaded. Can be NULL.
959 *
960 * Load content file (for libretro core).
961 *
962 * Returns : true if successful, otherwise false.
963 **/
content_file_load(content_state_t * p_content,struct string_list * content,content_information_ctx_t * content_ctx,enum msg_hash_enums * error_enum,char ** error_string,const struct retro_subsystem_info * special)964 static bool content_file_load(
965 content_state_t *p_content,
966 struct string_list *content,
967 content_information_ctx_t *content_ctx,
968 enum msg_hash_enums *error_enum,
969 char **error_string,
970 const struct retro_subsystem_info *special)
971 {
972 size_t i;
973 char msg[1024];
974 retro_ctx_load_content_info_t load_info;
975 bool used_vfs_fallback_copy = false;
976 #ifdef __WINRT__
977 rarch_system_info_t *system = runloop_get_system_info();
978 #endif
979 enum rarch_content_type first_content_type = RARCH_CONTENT_NONE;
980
981 msg[0] = '\0';
982
983 for (i = 0; i < content->size; i++)
984 {
985 const char *content_path = NULL;
986 uint8_t *content_data = NULL;
987 size_t content_size = 0;
988 const char *valid_exts = special ?
989 special->roms[i].valid_extensions :
990 content_ctx->valid_extensions;
991 bool content_compressed = false;
992
993 /* Get content path */
994 content_file_get_path(content, i, valid_exts,
995 &content_path, &content_compressed);
996
997 /* If content is missing and core requires content,
998 * return an error */
999 if (string_is_empty(content_path))
1000 {
1001 if (CONTENT_FILE_ATTR_GET_REQUIRED(content->elems[i].attr))
1002 {
1003 *error_enum = MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT;
1004 return false;
1005 }
1006 }
1007 else
1008 {
1009 /* If this is the first item of content,
1010 * get content type */
1011 if (i == 0)
1012 first_content_type = path_is_media_type(content_path);
1013
1014 /* Apply any file-type-specific content
1015 * handling overrides */
1016 content_file_apply_overrides(p_content, content, i, content_path);
1017
1018 /* If core does not require 'fullpath', load
1019 * the content into memory */
1020 if (!CONTENT_FILE_ATTR_GET_NEED_FULLPATH(content->elems[i].attr))
1021 {
1022 if (!content_file_load_into_memory(
1023 content_ctx, p_content, content_path,
1024 content_compressed, i, first_content_type,
1025 &content_data, &content_size))
1026 {
1027 snprintf(msg, sizeof(msg), "%s \"%s\"\n",
1028 msg_hash_to_str(MSG_COULD_NOT_READ_CONTENT_FILE),
1029 content_path);
1030 *error_string = strdup(msg);
1031 return false;
1032 }
1033 }
1034 else
1035 {
1036 #ifdef HAVE_COMPRESSION
1037 /* If this is compressed content and need_fullpath
1038 * is true, extract it to a temporary file */
1039 if (content_compressed &&
1040 !CONTENT_FILE_ATTR_GET_BLOCK_EXTRACT(content->elems[i].attr) &&
1041 !content_file_extract_from_archive(content_ctx, p_content,
1042 valid_exts, &content_path, error_string))
1043 return false;
1044 #endif
1045 #ifdef __WINRT__
1046 /* TODO: When support for the 'actual' VFS is added,
1047 * there will need to be some more logic here */
1048 if (!system->supports_vfs &&
1049 !is_path_accessible_using_standard_io(content_path))
1050 {
1051 /* Fallback to a file copy into an accessible directory */
1052 char *buf;
1053 int64_t len;
1054 char new_basedir[PATH_MAX_LENGTH];
1055 char new_path[PATH_MAX_LENGTH];
1056
1057 new_path[0] = '\0';
1058 new_basedir[0] = '\0';
1059
1060 RARCH_LOG("[CONTENT LOAD]: Core does not support VFS"
1061 " - copying to cache directory\n");
1062
1063 if (!string_is_empty(content_ctx->directory_cache))
1064 strlcpy(new_basedir, content_ctx->directory_cache,
1065 sizeof(new_basedir));
1066
1067 if (string_is_empty(new_basedir) ||
1068 !path_is_directory(new_basedir) ||
1069 !is_path_accessible_using_standard_io(new_basedir))
1070 {
1071 RARCH_WARN("[CONTENT LOAD]: Tried copying to cache directory, "
1072 "but cache directory was not set or found. "
1073 "Setting cache directory to root of writable app directory...\n");
1074 strlcpy(new_basedir, uwp_dir_data, sizeof(new_basedir));
1075 }
1076
1077 fill_pathname_join(new_path, new_basedir,
1078 path_basename(content_path), sizeof(new_path));
1079
1080 /* TODO: This may fail on very large files...
1081 * but copying large files is not a good idea anyway */
1082 if (!filestream_read_file(content_path, &buf, &len))
1083 {
1084 snprintf(msg, sizeof(msg), "%s \"%s\". (during copy read)\n",
1085 msg_hash_to_str(MSG_COULD_NOT_READ_CONTENT_FILE),
1086 content_path);
1087 *error_string = strdup(msg);
1088 return false;
1089 }
1090
1091 if (!filestream_write_file(new_path, buf, len))
1092 {
1093 free(buf);
1094 snprintf(msg, sizeof(msg), "%s \"%s\". (during copy write)\n",
1095 msg_hash_to_str(MSG_COULD_NOT_READ_CONTENT_FILE),
1096 content_path);
1097 *error_string = strdup(msg);
1098 return false;
1099 }
1100
1101 free(buf);
1102
1103 content_path = content_file_list_append_temporary(
1104 p_content->content_list, new_path);
1105
1106 used_vfs_fallback_copy = true;
1107 }
1108 #endif
1109 RARCH_LOG("[CONTENT LOAD]: %s\n", msg_hash_to_str(
1110 MSG_CONTENT_LOADING_SKIPPED_IMPLEMENTATION_WILL_DO_IT));
1111
1112 /* First content file is significant: need to
1113 * perform CRC calculation, but defer this
1114 * until value is used */
1115 if (i == 0)
1116 {
1117 /* If we have a media type, ignore CRC32 calculation. */
1118 if (first_content_type == RARCH_CONTENT_NONE)
1119 {
1120 strlcpy(p_content->pending_rom_crc_path, content_path,
1121 sizeof(p_content->pending_rom_crc_path));
1122 p_content->pending_rom_crc = true;
1123 }
1124 else
1125 p_content->rom_crc = 0;
1126 }
1127 }
1128 }
1129
1130 /* Add current entry to content file list */
1131 if (!content_file_list_set_info(
1132 p_content->content_list,
1133 content_path, content_data, content_size,
1134 CONTENT_FILE_ATTR_GET_PERSISTENT(content->elems[i].attr), i))
1135 {
1136 RARCH_LOG("[CONTENT LOAD]: Failed to process content file: %s\n", content_path);
1137 if (content_data)
1138 free((void*)content_data);
1139 *error_enum = MSG_FAILED_TO_LOAD_CONTENT;
1140 return false;
1141 }
1142 }
1143
1144 /* Load content into core */
1145 load_info.content = content;
1146 load_info.special = special;
1147 load_info.info = p_content->content_list->game_info;
1148
1149 if (!core_load_game(&load_info))
1150 {
1151 /* This is probably going to fail on multifile ROMs etc.
1152 * so give a visible explanation of what is likely wrong */
1153 if (used_vfs_fallback_copy)
1154 *error_enum = MSG_ERROR_LIBRETRO_CORE_REQUIRES_VFS;
1155 else
1156 *error_enum = MSG_FAILED_TO_LOAD_CONTENT;
1157
1158 return false;
1159 }
1160
1161 #ifdef HAVE_CHEEVOS
1162 if (!special)
1163 {
1164 const char *first_content_path =
1165 p_content->content_list->entries[0].full_path;
1166 if (!string_is_empty(first_content_path))
1167 {
1168 if (first_content_type == RARCH_CONTENT_NONE)
1169 {
1170 rcheevos_load(p_content->content_list->game_info);
1171 return true;
1172 }
1173 }
1174 }
1175 rcheevos_pause_hardcore();
1176 #endif
1177
1178 return true;
1179 }
1180
content_file_init_subsystem(const struct retro_subsystem_info * subsystem_data,size_t subsystem_current_count,enum msg_hash_enums * error_enum,char ** error_string,bool * ret)1181 static const struct retro_subsystem_info *content_file_init_subsystem(
1182 const struct retro_subsystem_info *subsystem_data,
1183 size_t subsystem_current_count,
1184 enum msg_hash_enums *error_enum,
1185 char **error_string,
1186 bool *ret)
1187 {
1188 struct string_list *subsystem = path_get_subsystem_list();
1189 const struct retro_subsystem_info *special = libretro_find_subsystem_info(
1190 subsystem_data, (unsigned)subsystem_current_count,
1191 path_get(RARCH_PATH_SUBSYSTEM));
1192 char msg[1024];
1193
1194 msg[0] = '\0';
1195
1196 if (!special)
1197 {
1198 snprintf(msg, sizeof(msg),
1199 "Failed to find subsystem \"%s\" in libretro implementation.\n",
1200 path_get(RARCH_PATH_SUBSYSTEM));
1201 *error_string = strdup(msg);
1202 goto error;
1203 }
1204
1205 if (special->num_roms)
1206 {
1207 if (!subsystem)
1208 {
1209 *error_enum = MSG_ERROR_LIBRETRO_CORE_REQUIRES_SPECIAL_CONTENT;
1210 goto error;
1211 }
1212
1213 if (special->num_roms != subsystem->size)
1214 {
1215 snprintf(msg, sizeof(msg),
1216 "Libretro core requires %u content files for "
1217 "subsystem \"%s\", but %u content files were provided.\n",
1218 special->num_roms, special->desc,
1219 (unsigned)subsystem->size);
1220 *error_string = strdup(msg);
1221 goto error;
1222 }
1223 }
1224 else if (subsystem && subsystem->size)
1225 {
1226 snprintf(msg, sizeof(msg),
1227 "Libretro core takes no content for subsystem \"%s\", "
1228 "but %u content files were provided.\n",
1229 special->desc,
1230 (unsigned)subsystem->size);
1231 *error_string = strdup(msg);
1232 goto error;
1233 }
1234
1235 *ret = true;
1236 return special;
1237
1238 error:
1239 *ret = false;
1240 return NULL;
1241 }
1242
content_file_set_attributes(struct string_list * content,const struct retro_subsystem_info * special,content_information_ctx_t * content_ctx,char ** error_string)1243 static void content_file_set_attributes(
1244 struct string_list *content,
1245 const struct retro_subsystem_info *special,
1246 content_information_ctx_t *content_ctx,
1247 char **error_string)
1248 {
1249 struct string_list *subsystem = path_get_subsystem_list();
1250
1251 if (!path_is_empty(RARCH_PATH_SUBSYSTEM) && special)
1252 {
1253 size_t i;
1254
1255 for (i = 0; i < subsystem->size; i++)
1256 {
1257 union string_list_elem_attr attr;
1258
1259 CONTENT_FILE_ATTR_RESET(attr);
1260 CONTENT_FILE_ATTR_SET_BLOCK_EXTRACT(attr, special->roms[i].block_extract);
1261 CONTENT_FILE_ATTR_SET_NEED_FULLPATH(attr, special->roms[i].need_fullpath);
1262 CONTENT_FILE_ATTR_SET_REQUIRED(attr, special->roms[i].required);
1263
1264 string_list_append(content, subsystem->elems[i].data, attr);
1265 }
1266 }
1267 else
1268 {
1269 const char *content_path = path_get(RARCH_PATH_CONTENT);
1270 bool contentless = false;
1271 bool is_inited = false;
1272 union string_list_elem_attr attr;
1273
1274 content_get_status(&contentless, &is_inited);
1275
1276 CONTENT_FILE_ATTR_RESET(attr);
1277 CONTENT_FILE_ATTR_SET_BLOCK_EXTRACT(attr, content_ctx->block_extract);
1278 CONTENT_FILE_ATTR_SET_NEED_FULLPATH(attr, content_ctx->need_fullpath);
1279 CONTENT_FILE_ATTR_SET_REQUIRED(attr, !contentless);
1280
1281 #if defined(HAVE_RUNAHEAD)
1282 /* If runahead is supported and we are not using
1283 * subsystems, content data buffer must *always*
1284 * be persistent, since user may toggle second
1285 * instance runahead at any time (and secondary
1286 * core initialisation requires valid data) */
1287 CONTENT_FILE_ATTR_SET_PERSISTENT(attr, true);
1288 #endif
1289
1290 if (string_is_empty(content_path))
1291 {
1292 if (contentless &&
1293 content_ctx->set_supports_no_game_enable)
1294 string_list_append(content, "", attr);
1295 }
1296 else
1297 string_list_append(content, content_path, attr);
1298 }
1299 }
1300
1301 /**
1302 * content_init_file:
1303 *
1304 * Initializes and loads a content file for the currently
1305 * selected libretro core.
1306 *
1307 * Returns : true if successful, otherwise false.
1308 **/
content_file_init(content_information_ctx_t * content_ctx,content_state_t * p_content,struct string_list * content,enum msg_hash_enums * error_enum,char ** error_string)1309 static bool content_file_init(
1310 content_information_ctx_t *content_ctx,
1311 content_state_t *p_content,
1312 struct string_list *content,
1313 enum msg_hash_enums *error_enum,
1314 char **error_string)
1315 {
1316 bool subsystem_path_is_empty = path_is_empty(RARCH_PATH_SUBSYSTEM);
1317 bool ret = subsystem_path_is_empty;
1318 const struct retro_subsystem_info *special = subsystem_path_is_empty ?
1319 NULL : content_file_init_subsystem(content_ctx->subsystem.data,
1320 content_ctx->subsystem.size, error_enum, error_string, &ret);
1321
1322 if (!ret)
1323 return false;
1324
1325 content_file_set_attributes(content, special, content_ctx, error_string);
1326
1327 if (content->size > 0)
1328 p_content->content_list = content_file_list_init(content->size);
1329
1330 if (p_content->content_list)
1331 {
1332 ret = content_file_load(p_content, content, content_ctx,
1333 error_enum, error_string, special);
1334
1335 content_file_list_free_transient_data(p_content->content_list);
1336 }
1337 else if (!special)
1338 {
1339 *error_enum = MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT;
1340 ret = false;
1341 }
1342
1343 return ret;
1344 }
1345
1346 /******************************/
1347 /* Content file functions END */
1348 /******************************/
1349
1350 /**
1351 * content_load_init_wrap:
1352 * @args : Input arguments.
1353 * @argc : Count of arguments.
1354 * @argv : Arguments.
1355 *
1356 * Generates an @argc and @argv pair based on @args
1357 * of type rarch_main_wrap.
1358 **/
content_load_init_wrap(const struct rarch_main_wrap * args,int * argc,char ** argv,bool print_args)1359 static void content_load_init_wrap(
1360 const struct rarch_main_wrap *args,
1361 int *argc, char **argv,
1362 bool print_args)
1363 {
1364 *argc = 0;
1365 argv[(*argc)++] = strdup("retroarch");
1366
1367 if (args->content_path)
1368 {
1369 RARCH_LOG("[CORE]: Using content: %s.\n", args->content_path);
1370 argv[(*argc)++] = strdup(args->content_path);
1371 }
1372 #ifdef HAVE_MENU
1373 else
1374 {
1375 RARCH_LOG("[CORE]: %s\n",
1376 msg_hash_to_str(MSG_NO_CONTENT_STARTING_DUMMY_CORE));
1377 argv[(*argc)++] = strdup("--menu");
1378 }
1379 #endif
1380
1381 if (args->sram_path)
1382 {
1383 argv[(*argc)++] = strdup("-s");
1384 argv[(*argc)++] = strdup(args->sram_path);
1385 }
1386
1387 if (args->state_path)
1388 {
1389 argv[(*argc)++] = strdup("-S");
1390 argv[(*argc)++] = strdup(args->state_path);
1391 }
1392
1393 if (args->config_path)
1394 {
1395 argv[(*argc)++] = strdup("-c");
1396 argv[(*argc)++] = strdup(args->config_path);
1397 }
1398
1399 #ifdef HAVE_DYNAMIC
1400 if (args->libretro_path)
1401 {
1402 argv[(*argc)++] = strdup("-L");
1403 argv[(*argc)++] = strdup(args->libretro_path);
1404 }
1405 #endif
1406
1407 if (args->verbose)
1408 argv[(*argc)++] = strdup("-v");
1409
1410 if (print_args)
1411 {
1412 int i;
1413 for (i = 0; i < *argc; i++)
1414 RARCH_LOG("[CORE]: Arg #%d: %s\n", i, argv[i]);
1415 }
1416 }
1417
1418 /**
1419 * content_load:
1420 *
1421 * Loads content file and starts up RetroArch.
1422 * If no content file can be loaded, will start up RetroArch
1423 * as-is.
1424 *
1425 * Returns: false (0) if retroarch_main_init failed,
1426 * otherwise true (1).
1427 **/
content_load(content_ctx_info_t * info,content_state_t * p_content)1428 static bool content_load(content_ctx_info_t *info,
1429 content_state_t *p_content)
1430 {
1431 unsigned i = 0;
1432 bool success = false;
1433 int rarch_argc = 0;
1434 char *rarch_argv[MAX_ARGS] = {NULL};
1435 char *argv_copy [MAX_ARGS] = {NULL};
1436 char **rarch_argv_ptr = (char**)info->argv;
1437 int *rarch_argc_ptr = (int*)&info->argc;
1438 struct rarch_main_wrap *wrap_args = NULL;
1439
1440 if (!(wrap_args = (struct rarch_main_wrap*)
1441 malloc(sizeof(*wrap_args))))
1442 return false;
1443
1444 retro_assert(wrap_args);
1445
1446 wrap_args->argv = NULL;
1447 wrap_args->content_path = NULL;
1448 wrap_args->sram_path = NULL;
1449 wrap_args->state_path = NULL;
1450 wrap_args->config_path = NULL;
1451 wrap_args->libretro_path = NULL;
1452 wrap_args->verbose = false;
1453 wrap_args->no_content = false;
1454 wrap_args->touched = false;
1455 wrap_args->argc = 0;
1456
1457 if (info->environ_get)
1458 info->environ_get(rarch_argc_ptr,
1459 rarch_argv_ptr, info->args, wrap_args);
1460
1461 if (wrap_args->touched)
1462 {
1463 content_load_init_wrap(wrap_args, &rarch_argc, rarch_argv,
1464 false);
1465 memcpy(argv_copy, rarch_argv, sizeof(rarch_argv));
1466 rarch_argv_ptr = (char**)rarch_argv;
1467 rarch_argc_ptr = (int*)&rarch_argc;
1468 }
1469
1470 rarch_ctl(RARCH_CTL_MAIN_DEINIT, NULL);
1471
1472 wrap_args->argc = *rarch_argc_ptr;
1473 wrap_args->argv = rarch_argv_ptr;
1474
1475 success = retroarch_main_init(wrap_args->argc, wrap_args->argv);
1476
1477 for (i = 0; i < ARRAY_SIZE(argv_copy); i++)
1478 free(argv_copy[i]);
1479 free(wrap_args);
1480
1481 if (!success)
1482 return false;
1483
1484 if (p_content->pending_subsystem_init)
1485 {
1486 command_event(CMD_EVENT_CORE_INIT, NULL);
1487 content_clear_subsystem();
1488 }
1489
1490 #ifdef HAVE_GFX_WIDGETS
1491 #ifdef HAVE_CONFIGFILE
1492 /* If retroarch_main_init() returned true, we
1493 * can safely trigger a load content animation */
1494 if (gfx_widgets_ready())
1495 {
1496 /* Note: Have to read settings value here
1497 * (It will be invalid if we try to read
1498 * it earlier...) */
1499 settings_t *settings = config_get_ptr();
1500 bool show_load_content_animation = settings && settings->bools.menu_show_load_content_animation;
1501 if (show_load_content_animation)
1502 gfx_widget_start_load_content_animation();
1503 }
1504 #endif
1505 #endif
1506
1507 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
1508 menu_shader_manager_init();
1509 #endif
1510
1511 command_event(CMD_EVENT_HISTORY_INIT, NULL);
1512 rarch_favorites_init();
1513 command_event(CMD_EVENT_RESUME, NULL);
1514 command_event(CMD_EVENT_VIDEO_SET_ASPECT_RATIO, NULL);
1515
1516 frontend_driver_process_args(rarch_argc_ptr, rarch_argv_ptr);
1517 frontend_driver_content_loaded();
1518
1519 return true;
1520 }
1521
1522 void menu_content_environment_get(int *argc, char *argv[],
1523 void *args, void *params_data);
1524
1525 /**
1526 * task_push_to_history_list:
1527 *
1528 * Will push the content entry to the history playlist.
1529 **/
task_push_to_history_list(content_state_t * p_content,bool launched_from_menu,bool launched_from_cli,bool launched_from_companion_ui)1530 static void task_push_to_history_list(
1531 content_state_t *p_content,
1532 bool launched_from_menu,
1533 bool launched_from_cli,
1534 bool launched_from_companion_ui)
1535 {
1536 bool contentless = false;
1537 bool is_inited = false;
1538
1539 content_get_status(&contentless, &is_inited);
1540
1541 /* Push entry to top of history playlist */
1542 if (is_inited || contentless)
1543 {
1544 char tmp[PATH_MAX_LENGTH];
1545 const char *path_content = path_get(RARCH_PATH_CONTENT);
1546 struct retro_system_info *info = runloop_get_libretro_system_info();
1547
1548 tmp[0] = '\0';
1549
1550 if (!string_is_empty(path_content))
1551 strlcpy(tmp, path_content, sizeof(tmp));
1552
1553 /* Path can be relative here.
1554 * Ensure we're pushing absolute path. */
1555 if (!launched_from_menu && !string_is_empty(tmp))
1556 path_resolve_realpath(tmp, sizeof(tmp), true);
1557
1558 #ifdef HAVE_MENU
1559 /* Push quick menu onto menu stack */
1560 if (launched_from_cli)
1561 menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUICK_MENU, NULL);
1562 #endif
1563
1564 if (info && !string_is_empty(tmp))
1565 {
1566 const char *core_path = NULL;
1567 const char *core_name = NULL;
1568 const char *label = NULL;
1569 const char *crc32 = NULL;
1570 const char *db_name = NULL;
1571 playlist_t *playlist_hist = g_defaults.content_history;
1572 settings_t *settings = config_get_ptr();
1573 global_t *global = global_get_ptr();
1574
1575 switch (path_is_media_type(tmp))
1576 {
1577 case RARCH_CONTENT_MOVIE:
1578 #ifdef HAVE_FFMPEG
1579 playlist_hist = g_defaults.video_history;
1580 core_name = "movieplayer";
1581 core_path = "builtin";
1582 #endif
1583 break;
1584 case RARCH_CONTENT_MUSIC:
1585 playlist_hist = g_defaults.music_history;
1586 core_name = "musicplayer";
1587 core_path = "builtin";
1588 break;
1589 case RARCH_CONTENT_IMAGE:
1590 #ifdef HAVE_IMAGEVIEWER
1591 playlist_hist = g_defaults.image_history;
1592 core_name = "imageviewer";
1593 core_path = "builtin";
1594 #endif
1595 break;
1596 default:
1597 {
1598 core_info_t *core_info = NULL;
1599 /* Set core display name
1600 * (As far as I can tell, core_info_get_current_core()
1601 * should always provide a valid pointer here...) */
1602 core_info_get_current_core(&core_info);
1603
1604 /* Set core path */
1605 core_path = path_get(RARCH_PATH_CORE);
1606
1607 if (core_info)
1608 core_name = core_info->display_name;
1609
1610 if (string_is_empty(core_name))
1611 core_name = info->library_name;
1612
1613 if (launched_from_companion_ui)
1614 {
1615 /* Database name + checksum are supplied
1616 * by the companion UI itself */
1617 if (!string_is_empty(p_content->companion_ui_crc32))
1618 crc32 = p_content->companion_ui_crc32;
1619
1620 if (!string_is_empty(p_content->companion_ui_db_name))
1621 db_name = p_content->companion_ui_db_name;
1622 }
1623 #ifdef HAVE_MENU
1624 else
1625 {
1626 menu_handle_t *menu = menu_driver_get_ptr();
1627 /* Set database name + checksum */
1628 if (menu)
1629 {
1630 playlist_t *playlist_curr = playlist_get_cached();
1631
1632 if (playlist_index_is_valid(playlist_curr, menu->rpl_entry_selection_ptr, tmp, core_path))
1633 {
1634 playlist_get_crc32(playlist_curr, menu->rpl_entry_selection_ptr, &crc32);
1635 playlist_get_db_name(playlist_curr, menu->rpl_entry_selection_ptr, &db_name);
1636 }
1637 }
1638 }
1639 #endif
1640 break;
1641 }
1642 }
1643
1644 if (global && !string_is_empty(global->name.label))
1645 label = global->name.label;
1646
1647 if (
1648 settings && settings->bools.history_list_enable
1649 && playlist_hist)
1650 {
1651 char subsystem_name[PATH_MAX_LENGTH];
1652 struct playlist_entry entry = {0};
1653
1654 subsystem_name[0] = '\0';
1655
1656 content_get_subsystem_friendly_name(path_get(RARCH_PATH_SUBSYSTEM), subsystem_name, sizeof(subsystem_name));
1657
1658 /* The push function reads our entry as const,
1659 * so these casts are safe */
1660 entry.path = (char*)tmp;
1661 entry.label = (char*)label;
1662 entry.core_path = (char*)core_path;
1663 entry.core_name = (char*)core_name;
1664 entry.crc32 = (char*)crc32;
1665 entry.db_name = (char*)db_name;
1666 entry.subsystem_ident = (char*)path_get(RARCH_PATH_SUBSYSTEM);
1667 entry.subsystem_name = (char*)subsystem_name;
1668 entry.subsystem_roms = (struct string_list*)path_get_subsystem_list();
1669
1670 command_playlist_push_write(playlist_hist, &entry);
1671 }
1672 }
1673 }
1674 }
1675
1676 #ifdef HAVE_MENU
command_event_cmd_exec(content_state_t * p_content,const char * data,content_information_ctx_t * content_ctx,bool launched_from_cli,char ** error_string)1677 static bool command_event_cmd_exec(
1678 content_state_t *p_content,
1679 const char *data,
1680 content_information_ctx_t *content_ctx,
1681 bool launched_from_cli,
1682 char **error_string)
1683 {
1684 if (path_get(RARCH_PATH_CONTENT) != data)
1685 {
1686 path_clear(RARCH_PATH_CONTENT);
1687 if (!string_is_empty(data))
1688 path_set(RARCH_PATH_CONTENT, data);
1689 }
1690
1691 #if defined(HAVE_DYNAMIC)
1692 {
1693 content_ctx_info_t content_info;
1694
1695 content_info.argc = 0;
1696 content_info.argv = NULL;
1697 content_info.args = NULL;
1698 content_info.environ_get = menu_content_environment_get;
1699
1700 /* Loads content into currently selected core. */
1701 if (!content_load(&content_info, p_content))
1702 return false;
1703 task_push_to_history_list(p_content, true, launched_from_cli, false);
1704 }
1705 #else
1706 frontend_driver_set_fork(FRONTEND_FORK_CORE_WITH_ARGS);
1707 #endif
1708
1709 return true;
1710 }
1711 #endif
1712
firmware_update_status(content_information_ctx_t * content_ctx)1713 static bool firmware_update_status(
1714 content_information_ctx_t *content_ctx)
1715 {
1716 char s[PATH_MAX_LENGTH];
1717 core_info_ctx_firmware_t firmware_info;
1718 bool set_missing_firmware = false;
1719 core_info_t *core_info = NULL;
1720
1721 core_info_get_current_core(&core_info);
1722
1723 if (!core_info)
1724 return false;
1725
1726 s[0] = '\0';
1727 firmware_info.path = core_info->path;
1728
1729 if (!string_is_empty(content_ctx->directory_system))
1730 firmware_info.directory.system = content_ctx->directory_system;
1731 else
1732 {
1733 strlcpy(s, path_get(RARCH_PATH_CONTENT), sizeof(s));
1734 path_basedir_wrapper(s);
1735 firmware_info.directory.system = s;
1736 }
1737
1738 RARCH_LOG("[CONTENT LOAD]: Updating firmware status for: %s on %s\n",
1739 core_info->path,
1740 firmware_info.directory.system);
1741
1742 rarch_ctl(RARCH_CTL_UNSET_MISSING_BIOS, NULL);
1743
1744 core_info_list_update_missing_firmware(&firmware_info,
1745 &set_missing_firmware);
1746
1747 if (set_missing_firmware)
1748 rarch_ctl(RARCH_CTL_SET_MISSING_BIOS, NULL);
1749
1750 if (
1751 content_ctx->bios_is_missing &&
1752 content_ctx->check_firmware_before_loading)
1753 {
1754 runloop_msg_queue_push(
1755 msg_hash_to_str(MSG_FIRMWARE),
1756 100, 500, true, NULL,
1757 MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1758 RARCH_LOG("[CONTENT LOAD]: Load content blocked. Reason: %s\n",
1759 msg_hash_to_str(MSG_FIRMWARE));
1760
1761 return true;
1762 }
1763
1764 return false;
1765 }
1766
task_push_start_dummy_core(content_ctx_info_t * content_info)1767 bool task_push_start_dummy_core(content_ctx_info_t *content_info)
1768 {
1769 content_information_ctx_t content_ctx;
1770 content_state_t *p_content = content_state_get_ptr();
1771 bool ret = true;
1772 char *error_string = NULL;
1773 global_t *global = global_get_ptr();
1774 settings_t *settings = config_get_ptr();
1775 rarch_system_info_t *sys_info = runloop_get_system_info();
1776 const char *path_dir_system = settings->paths.directory_system;
1777 bool check_firmware_before_loading = settings->bools.check_firmware_before_loading;
1778
1779 if (!content_info)
1780 return false;
1781
1782 content_ctx.check_firmware_before_loading = check_firmware_before_loading;
1783 #ifdef HAVE_PATCH
1784 content_ctx.is_ips_pref = rarch_ctl(RARCH_CTL_IS_IPS_PREF, NULL);
1785 content_ctx.is_bps_pref = rarch_ctl(RARCH_CTL_IS_BPS_PREF, NULL);
1786 content_ctx.is_ups_pref = rarch_ctl(RARCH_CTL_IS_UPS_PREF, NULL);
1787 content_ctx.patch_is_blocked = rarch_ctl(RARCH_CTL_IS_PATCH_BLOCKED, NULL);
1788 #endif
1789 content_ctx.bios_is_missing = rarch_ctl(RARCH_CTL_IS_MISSING_BIOS, NULL);
1790 content_ctx.directory_system = NULL;
1791 content_ctx.directory_cache = NULL;
1792 content_ctx.name_ips = NULL;
1793 content_ctx.name_bps = NULL;
1794 content_ctx.name_ups = NULL;
1795 content_ctx.valid_extensions = NULL;
1796 content_ctx.block_extract = false;
1797 content_ctx.need_fullpath = false;
1798 content_ctx.set_supports_no_game_enable = false;
1799
1800 content_ctx.subsystem.data = NULL;
1801 content_ctx.subsystem.size = 0;
1802
1803 if (global)
1804 {
1805 if (!string_is_empty(global->name.ips))
1806 content_ctx.name_ips = strdup(global->name.ips);
1807 if (!string_is_empty(global->name.bps))
1808 content_ctx.name_bps = strdup(global->name.bps);
1809 if (!string_is_empty(global->name.ups))
1810 content_ctx.name_ups = strdup(global->name.ups);
1811 }
1812
1813 if (!string_is_empty(path_dir_system))
1814 content_ctx.directory_system = strdup(path_dir_system);
1815
1816 if (!content_info->environ_get)
1817 content_info->environ_get = menu_content_environment_get;
1818
1819 /* Clear content path */
1820 path_clear(RARCH_PATH_CONTENT);
1821
1822 /* Preliminary stuff that has to be done before we
1823 * load the actual content. Can differ per mode. */
1824 sys_info->load_no_content = false;
1825 rarch_ctl(RARCH_CTL_STATE_FREE, NULL);
1826 task_queue_deinit();
1827 retroarch_init_task_queue();
1828
1829 /* Loads content into currently selected core. */
1830 if ((ret = content_load(content_info, p_content)))
1831 task_push_to_history_list(p_content, false, false, false);
1832
1833 /* Handle load content failure */
1834 if (!ret)
1835 {
1836 if (error_string)
1837 {
1838 runloop_msg_queue_push(error_string, 2, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1839 RARCH_ERR("[CONTENT LOAD]: %s\n", error_string);
1840 free(error_string);
1841 }
1842 }
1843
1844 if (content_ctx.name_ips)
1845 free(content_ctx.name_ips);
1846 if (content_ctx.name_bps)
1847 free(content_ctx.name_bps);
1848 if (content_ctx.name_ups)
1849 free(content_ctx.name_ups);
1850 if (content_ctx.directory_system)
1851 free(content_ctx.directory_system);
1852
1853 return ret;
1854 }
1855
1856 #ifdef HAVE_MENU
1857
task_push_load_content_from_playlist_from_menu(const char * core_path,const char * fullpath,const char * label,content_ctx_info_t * content_info,retro_task_callback_t cb,void * user_data)1858 bool task_push_load_content_from_playlist_from_menu(
1859 const char *core_path,
1860 const char *fullpath,
1861 const char *label,
1862 content_ctx_info_t *content_info,
1863 retro_task_callback_t cb,
1864 void *user_data)
1865 {
1866 content_information_ctx_t content_ctx;
1867
1868 content_state_t *p_content = content_state_get_ptr();
1869 bool ret = true;
1870 char *error_string = NULL;
1871 global_t *global = global_get_ptr();
1872 settings_t *settings = config_get_ptr();
1873 rarch_system_info_t *sys_info = runloop_get_system_info();
1874 const char *path_dir_system = settings->paths.directory_system;
1875 #ifndef HAVE_DYNAMIC
1876 bool force_core_reload = settings->bools.always_reload_core_on_run_content;
1877 #endif
1878
1879 content_ctx.check_firmware_before_loading = settings->bools.check_firmware_before_loading;
1880 #ifdef HAVE_PATCH
1881 content_ctx.is_ips_pref = rarch_ctl(RARCH_CTL_IS_IPS_PREF, NULL);
1882 content_ctx.is_bps_pref = rarch_ctl(RARCH_CTL_IS_BPS_PREF, NULL);
1883 content_ctx.is_ups_pref = rarch_ctl(RARCH_CTL_IS_UPS_PREF, NULL);
1884 content_ctx.patch_is_blocked = rarch_ctl(RARCH_CTL_IS_PATCH_BLOCKED, NULL);
1885 #endif
1886 content_ctx.bios_is_missing = rarch_ctl(RARCH_CTL_IS_MISSING_BIOS, NULL);
1887 content_ctx.directory_system = NULL;
1888 content_ctx.directory_cache = NULL;
1889 content_ctx.name_ips = NULL;
1890 content_ctx.name_bps = NULL;
1891 content_ctx.name_ups = NULL;
1892 content_ctx.valid_extensions = NULL;
1893 content_ctx.block_extract = false;
1894 content_ctx.need_fullpath = false;
1895 content_ctx.set_supports_no_game_enable = false;
1896
1897 content_ctx.subsystem.data = NULL;
1898 content_ctx.subsystem.size = 0;
1899
1900 if (global)
1901 {
1902 if (!string_is_empty(global->name.ips))
1903 content_ctx.name_ips = strdup(global->name.ips);
1904 if (!string_is_empty(global->name.bps))
1905 content_ctx.name_bps = strdup(global->name.bps);
1906 if (!string_is_empty(global->name.ups))
1907 content_ctx.name_ups = strdup(global->name.ups);
1908 if (label)
1909 strlcpy(global->name.label, label, sizeof(global->name.label));
1910 else
1911 global->name.label[0] = '\0';
1912 }
1913
1914 if (!string_is_empty(path_dir_system))
1915 content_ctx.directory_system = strdup(path_dir_system);
1916
1917 /* Is content required by this core? */
1918 if (fullpath)
1919 sys_info->load_no_content = false;
1920 else
1921 sys_info->load_no_content = true;
1922
1923 #ifndef HAVE_DYNAMIC
1924 /* Check whether specified core is already loaded
1925 * > If so, content can be launched directly with
1926 * the currently loaded core */
1927 if (!force_core_reload &&
1928 rarch_ctl(RARCH_CTL_IS_CORE_LOADED, (void*)core_path))
1929 {
1930 if (!content_info->environ_get)
1931 content_info->environ_get = menu_content_environment_get;
1932
1933 /* Register content path */
1934 path_clear(RARCH_PATH_CONTENT);
1935 if (!string_is_empty(fullpath))
1936 path_set(RARCH_PATH_CONTENT, fullpath);
1937
1938 /* Load content */
1939 ret = content_load(content_info, p_content);
1940
1941 if (!ret)
1942 goto end;
1943
1944 /* Update content history */
1945 task_push_to_history_list(p_content, true, false, false);
1946
1947 goto end;
1948 }
1949 #endif
1950
1951 /* Specified core is not loaded
1952 * > Load it */
1953 path_set(RARCH_PATH_CORE, core_path);
1954 #ifdef HAVE_DYNAMIC
1955 command_event(CMD_EVENT_LOAD_CORE, NULL);
1956 #endif
1957
1958 /* Load content
1959 * > On targets that do not support dynamic core loading,
1960 * command_event_cmd_exec() will fork a new instance */
1961 if (!(ret = command_event_cmd_exec(p_content,
1962 fullpath, &content_ctx, false, &error_string)))
1963 goto end;
1964
1965 #ifdef HAVE_COCOATOUCH
1966 /* This seems to be needed for iOS for some reason
1967 * to show the quick menu after the menu is shown */
1968 menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUICK_MENU, NULL);
1969 #endif
1970
1971 #ifndef HAVE_DYNAMIC
1972 /* No dynamic core loading support: if we reach
1973 * this point then a new instance has been
1974 * forked - have to shut down this one */
1975 rarch_ctl(RARCH_CTL_SET_SHUTDOWN, NULL);
1976 retroarch_menu_running_finished(true);
1977 #endif
1978
1979 end:
1980 /* Handle load content failure */
1981 if (!ret)
1982 {
1983 if (error_string)
1984 {
1985 runloop_msg_queue_push(error_string, 2, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
1986 RARCH_ERR("[CONTENT LOAD]: %s\n", error_string);
1987 free(error_string);
1988 }
1989
1990 retroarch_menu_running();
1991 }
1992
1993 if (content_ctx.name_ips)
1994 free(content_ctx.name_ips);
1995 if (content_ctx.name_bps)
1996 free(content_ctx.name_bps);
1997 if (content_ctx.name_ups)
1998 free(content_ctx.name_ups);
1999 if (content_ctx.directory_system)
2000 free(content_ctx.directory_system);
2001
2002 return ret;
2003 }
2004 #endif
2005
task_push_start_current_core(content_ctx_info_t * content_info)2006 bool task_push_start_current_core(content_ctx_info_t *content_info)
2007 {
2008 content_information_ctx_t content_ctx;
2009
2010 content_state_t *p_content = content_state_get_ptr();
2011 bool ret = true;
2012 char *error_string = NULL;
2013 global_t *global = global_get_ptr();
2014 settings_t *settings = config_get_ptr();
2015 const char *path_dir_system = settings->paths.directory_system;
2016 bool check_firmware_before_loading = settings->bools.check_firmware_before_loading;
2017
2018 if (!content_info)
2019 return false;
2020
2021 content_ctx.check_firmware_before_loading = check_firmware_before_loading;
2022 #ifdef HAVE_PATCH
2023 content_ctx.is_ips_pref = rarch_ctl(RARCH_CTL_IS_IPS_PREF, NULL);
2024 content_ctx.is_bps_pref = rarch_ctl(RARCH_CTL_IS_BPS_PREF, NULL);
2025 content_ctx.is_ups_pref = rarch_ctl(RARCH_CTL_IS_UPS_PREF, NULL);
2026 content_ctx.patch_is_blocked = rarch_ctl(RARCH_CTL_IS_PATCH_BLOCKED, NULL);
2027 #endif
2028 content_ctx.bios_is_missing = rarch_ctl(RARCH_CTL_IS_MISSING_BIOS, NULL);
2029 content_ctx.directory_system = NULL;
2030 content_ctx.directory_cache = NULL;
2031 content_ctx.name_ips = NULL;
2032 content_ctx.name_bps = NULL;
2033 content_ctx.name_ups = NULL;
2034 content_ctx.valid_extensions = NULL;
2035 content_ctx.block_extract = false;
2036 content_ctx.need_fullpath = false;
2037 content_ctx.set_supports_no_game_enable = false;
2038
2039 content_ctx.subsystem.data = NULL;
2040 content_ctx.subsystem.size = 0;
2041
2042 if (global)
2043 {
2044 if (!string_is_empty(global->name.ips))
2045 content_ctx.name_ips = strdup(global->name.ips);
2046 if (!string_is_empty(global->name.bps))
2047 content_ctx.name_bps = strdup(global->name.bps);
2048 if (!string_is_empty(global->name.ups))
2049 content_ctx.name_ups = strdup(global->name.ups);
2050 }
2051
2052 if (!string_is_empty(path_dir_system))
2053 content_ctx.directory_system = strdup(path_dir_system);
2054
2055 if (!content_info->environ_get)
2056 content_info->environ_get = menu_content_environment_get;
2057
2058 /* Clear content path */
2059 path_clear(RARCH_PATH_CONTENT);
2060
2061 /* Preliminary stuff that has to be done before we
2062 * load the actual content. Can differ per mode. */
2063 retroarch_set_current_core_type(CORE_TYPE_PLAIN, true);
2064
2065 /* Load content */
2066 if (firmware_update_status(&content_ctx))
2067 goto end;
2068
2069 /* Loads content into currently selected core. */
2070 if (!(ret = content_load(content_info, p_content)))
2071 {
2072 if (error_string)
2073 {
2074 runloop_msg_queue_push(error_string, 2, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2075 RARCH_ERR("[CONTENT LOAD]: %s\n", error_string);
2076 free(error_string);
2077 }
2078
2079 retroarch_menu_running();
2080 goto end;
2081 }
2082
2083 task_push_to_history_list(p_content, true, false, false);
2084
2085 #ifdef HAVE_MENU
2086 /* Push quick menu onto menu stack */
2087 menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUICK_MENU, NULL);
2088 #endif
2089
2090 end:
2091 if (content_ctx.name_ips)
2092 free(content_ctx.name_ips);
2093 if (content_ctx.name_bps)
2094 free(content_ctx.name_bps);
2095 if (content_ctx.name_ups)
2096 free(content_ctx.name_ups);
2097 if (content_ctx.directory_system)
2098 free(content_ctx.directory_system);
2099
2100 return ret;
2101 }
2102
task_push_load_new_core(const char * core_path,const char * fullpath,content_ctx_info_t * content_info,enum rarch_core_type type,retro_task_callback_t cb,void * user_data)2103 bool task_push_load_new_core(
2104 const char *core_path,
2105 const char *fullpath,
2106 content_ctx_info_t *content_info,
2107 enum rarch_core_type type,
2108 retro_task_callback_t cb,
2109 void *user_data)
2110 {
2111 path_set(RARCH_PATH_CORE, core_path);
2112
2113 /* Load core */
2114 command_event(CMD_EVENT_LOAD_CORE, NULL);
2115
2116 #ifndef HAVE_DYNAMIC
2117 /* Fork core? */
2118 if (!frontend_driver_set_fork(FRONTEND_FORK_CORE))
2119 return false;
2120 #endif
2121
2122 /* Preliminary stuff that has to be done before we
2123 * load the actual content. Can differ per mode. */
2124 retroarch_set_current_core_type(type, true);
2125
2126 return true;
2127 }
2128
2129 #ifdef HAVE_MENU
task_push_load_content_with_new_core_from_menu(const char * core_path,const char * fullpath,content_ctx_info_t * content_info,enum rarch_core_type type,retro_task_callback_t cb,void * user_data)2130 bool task_push_load_content_with_new_core_from_menu(
2131 const char *core_path,
2132 const char *fullpath,
2133 content_ctx_info_t *content_info,
2134 enum rarch_core_type type,
2135 retro_task_callback_t cb,
2136 void *user_data)
2137 {
2138 content_information_ctx_t content_ctx;
2139
2140 content_state_t *p_content = content_state_get_ptr();
2141 bool ret = true;
2142 char *error_string = NULL;
2143 global_t *global = global_get_ptr();
2144 settings_t *settings = config_get_ptr();
2145 bool check_firmware_before_loading = settings->bools.check_firmware_before_loading;
2146 const char *path_dir_system = settings->paths.directory_system;
2147 #ifndef HAVE_DYNAMIC
2148 bool force_core_reload = settings->bools.always_reload_core_on_run_content;
2149
2150 /* Check whether specified core is already loaded
2151 * > If so, we can skip loading the core and
2152 * just load the content directly */
2153 if (!force_core_reload &&
2154 (type == CORE_TYPE_PLAIN) &&
2155 rarch_ctl(RARCH_CTL_IS_CORE_LOADED, (void*)core_path))
2156 return task_push_load_content_with_core_from_menu(
2157 fullpath, content_info,
2158 type, cb, user_data);
2159 #endif
2160
2161 content_ctx.check_firmware_before_loading = check_firmware_before_loading;
2162 #ifdef HAVE_PATCH
2163 content_ctx.is_ips_pref = rarch_ctl(RARCH_CTL_IS_IPS_PREF, NULL);
2164 content_ctx.is_bps_pref = rarch_ctl(RARCH_CTL_IS_BPS_PREF, NULL);
2165 content_ctx.is_ups_pref = rarch_ctl(RARCH_CTL_IS_UPS_PREF, NULL);
2166 content_ctx.patch_is_blocked = rarch_ctl(RARCH_CTL_IS_PATCH_BLOCKED, NULL);
2167 #endif
2168 content_ctx.bios_is_missing = rarch_ctl(RARCH_CTL_IS_MISSING_BIOS, NULL);
2169 content_ctx.directory_system = NULL;
2170 content_ctx.directory_cache = NULL;
2171 content_ctx.name_ips = NULL;
2172 content_ctx.name_bps = NULL;
2173 content_ctx.name_ups = NULL;
2174 content_ctx.valid_extensions = NULL;
2175 content_ctx.block_extract = false;
2176 content_ctx.need_fullpath = false;
2177 content_ctx.set_supports_no_game_enable = false;
2178
2179 content_ctx.subsystem.data = NULL;
2180 content_ctx.subsystem.size = 0;
2181
2182 if (global)
2183 {
2184 if (!string_is_empty(global->name.ips))
2185 content_ctx.name_ips = strdup(global->name.ips);
2186 if (!string_is_empty(global->name.bps))
2187 content_ctx.name_bps = strdup(global->name.bps);
2188 if (!string_is_empty(global->name.ups))
2189 content_ctx.name_ups = strdup(global->name.ups);
2190
2191 global->name.label[0] = '\0';
2192 }
2193
2194 if (!string_is_empty(path_dir_system))
2195 content_ctx.directory_system = strdup(path_dir_system);
2196
2197 path_set(RARCH_PATH_CONTENT, fullpath);
2198 path_set(RARCH_PATH_CORE, core_path);
2199
2200 #ifdef HAVE_DYNAMIC
2201 /* Load core */
2202 command_event(CMD_EVENT_LOAD_CORE, NULL);
2203
2204 /* Load content */
2205 if (!content_info->environ_get)
2206 content_info->environ_get = menu_content_environment_get;
2207
2208 if (firmware_update_status(&content_ctx))
2209 goto end;
2210
2211 /* Loads content into currently selected core. */
2212 if (!(ret = content_load(content_info, p_content)))
2213 {
2214 if (error_string)
2215 {
2216 runloop_msg_queue_push(error_string, 2, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2217 RARCH_ERR("[CONTENT LOAD]: %s\n", error_string);
2218 free(error_string);
2219 }
2220
2221 retroarch_menu_running();
2222 goto end;
2223 }
2224
2225 task_push_to_history_list(p_content, true, false, false);
2226 #else
2227 command_event_cmd_exec(p_content,
2228 path_get(RARCH_PATH_CONTENT), &content_ctx,
2229 false, &error_string);
2230 command_event(CMD_EVENT_QUIT, NULL);
2231 #endif
2232
2233 /* Push quick menu onto menu stack */
2234 if (type != CORE_TYPE_DUMMY)
2235 menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUICK_MENU, NULL);
2236
2237 #ifdef HAVE_DYNAMIC
2238 end:
2239 #endif
2240 if (content_ctx.name_ips)
2241 free(content_ctx.name_ips);
2242 if (content_ctx.name_bps)
2243 free(content_ctx.name_bps);
2244 if (content_ctx.name_ups)
2245 free(content_ctx.name_ups);
2246 if (content_ctx.directory_system)
2247 free(content_ctx.directory_system);
2248
2249 return ret;
2250 }
2251 #endif
2252
task_load_content_internal(content_ctx_info_t * content_info,bool loading_from_menu,bool loading_from_cli,bool loading_from_companion_ui)2253 static bool task_load_content_internal(
2254 content_ctx_info_t *content_info,
2255 bool loading_from_menu,
2256 bool loading_from_cli,
2257 bool loading_from_companion_ui)
2258 {
2259 content_information_ctx_t content_ctx;
2260
2261 content_state_t *p_content = content_state_get_ptr();
2262 bool ret = false;
2263 char *error_string = NULL;
2264 global_t *global = global_get_ptr();
2265 rarch_system_info_t *sys_info = runloop_get_system_info();
2266 settings_t *settings = config_get_ptr();
2267 bool check_firmware_before_loading = settings->bools.check_firmware_before_loading;
2268 bool set_supports_no_game_enable = settings->bools.set_supports_no_game_enable;
2269 const char *path_dir_system = settings->paths.directory_system;
2270 const char *path_dir_cache = settings->paths.directory_cache;
2271
2272 content_ctx.check_firmware_before_loading = check_firmware_before_loading;
2273 #ifdef HAVE_PATCH
2274 content_ctx.is_ips_pref = rarch_ctl(RARCH_CTL_IS_IPS_PREF, NULL);
2275 content_ctx.is_bps_pref = rarch_ctl(RARCH_CTL_IS_BPS_PREF, NULL);
2276 content_ctx.is_ups_pref = rarch_ctl(RARCH_CTL_IS_UPS_PREF, NULL);
2277 content_ctx.patch_is_blocked = rarch_ctl(RARCH_CTL_IS_PATCH_BLOCKED, NULL);
2278 #endif
2279 content_ctx.bios_is_missing = rarch_ctl(RARCH_CTL_IS_MISSING_BIOS, NULL);
2280 content_ctx.directory_system = NULL;
2281 content_ctx.directory_cache = NULL;
2282 content_ctx.name_ips = NULL;
2283 content_ctx.name_bps = NULL;
2284 content_ctx.name_ups = NULL;
2285 content_ctx.valid_extensions = NULL;
2286 content_ctx.block_extract = false;
2287 content_ctx.need_fullpath = false;
2288 content_ctx.set_supports_no_game_enable = false;
2289
2290 content_ctx.subsystem.data = NULL;
2291 content_ctx.subsystem.size = 0;
2292
2293 if (sys_info)
2294 {
2295 struct retro_system_info *system = runloop_get_libretro_system_info();
2296
2297 content_ctx.set_supports_no_game_enable = set_supports_no_game_enable;
2298
2299 if (!string_is_empty(path_dir_cache))
2300 content_ctx.directory_cache = strdup(path_dir_cache);
2301 if (!string_is_empty(system->valid_extensions))
2302 content_ctx.valid_extensions = strdup(system->valid_extensions);
2303
2304 content_ctx.block_extract = system->block_extract;
2305 content_ctx.need_fullpath = system->need_fullpath;
2306
2307 content_ctx.subsystem.data = sys_info->subsystem.data;
2308 content_ctx.subsystem.size = sys_info->subsystem.size;
2309 }
2310
2311 if (global)
2312 {
2313 if (!string_is_empty(global->name.ips))
2314 content_ctx.name_ips = strdup(global->name.ips);
2315 if (!string_is_empty(global->name.bps))
2316 content_ctx.name_bps = strdup(global->name.bps);
2317 if (!string_is_empty(global->name.ups))
2318 content_ctx.name_ups = strdup(global->name.ups);
2319 }
2320
2321 if (!string_is_empty(path_dir_system))
2322 content_ctx.directory_system = strdup(path_dir_system);
2323
2324 if (!content_info->environ_get)
2325 content_info->environ_get = menu_content_environment_get;
2326
2327 if (firmware_update_status(&content_ctx))
2328 goto end;
2329
2330 #ifdef HAVE_DISCORD
2331 if (discord_is_inited)
2332 {
2333 discord_userdata_t userdata;
2334 userdata.status = DISCORD_PRESENCE_NETPLAY_NETPLAY_STOPPED;
2335 command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
2336 userdata.status = DISCORD_PRESENCE_MENU;
2337 command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
2338 }
2339 #endif
2340
2341 /* Loads content into currently selected core. */
2342 if ((ret = content_load(content_info, p_content)))
2343 task_push_to_history_list(p_content,
2344 true, loading_from_cli, loading_from_companion_ui);
2345
2346 end:
2347 if (content_ctx.name_ips)
2348 free(content_ctx.name_ips);
2349 if (content_ctx.name_bps)
2350 free(content_ctx.name_bps);
2351 if (content_ctx.name_ups)
2352 free(content_ctx.name_ups);
2353 if (content_ctx.directory_system)
2354 free(content_ctx.directory_system);
2355 if (content_ctx.directory_cache)
2356 free(content_ctx.directory_cache);
2357 if (content_ctx.valid_extensions)
2358 free(content_ctx.valid_extensions);
2359
2360 if (!ret)
2361 {
2362 if (error_string)
2363 {
2364 runloop_msg_queue_push(error_string, 2, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2365 RARCH_ERR("[CONTENT LOAD]: %s\n", error_string);
2366 free(error_string);
2367 }
2368
2369 return false;
2370 }
2371
2372 return true;
2373 }
2374
task_push_load_content_with_new_core_from_companion_ui(const char * core_path,const char * fullpath,const char * label,const char * db_name,const char * crc32,content_ctx_info_t * content_info,retro_task_callback_t cb,void * user_data)2375 bool task_push_load_content_with_new_core_from_companion_ui(
2376 const char *core_path,
2377 const char *fullpath,
2378 const char *label,
2379 const char *db_name,
2380 const char *crc32,
2381 content_ctx_info_t *content_info,
2382 retro_task_callback_t cb,
2383 void *user_data)
2384 {
2385 global_t *global = global_get_ptr();
2386 content_state_t *p_content = content_state_get_ptr();
2387
2388 path_set(RARCH_PATH_CONTENT, fullpath);
2389 path_set(RARCH_PATH_CORE, core_path);
2390
2391 p_content->companion_ui_db_name[0] = '\0';
2392 p_content->companion_ui_crc32[0] = '\0';
2393
2394 if (!string_is_empty(db_name))
2395 strlcpy(p_content->companion_ui_db_name,
2396 db_name, sizeof(p_content->companion_ui_db_name));
2397
2398 if (!string_is_empty(crc32))
2399 strlcpy(p_content->companion_ui_crc32,
2400 crc32, sizeof(p_content->companion_ui_crc32));
2401
2402 #ifdef HAVE_DYNAMIC
2403 command_event(CMD_EVENT_LOAD_CORE, NULL);
2404 #endif
2405
2406 global->launched_from_cli = false;
2407
2408 if (global)
2409 {
2410 if (label)
2411 strlcpy(global->name.label, label, sizeof(global->name.label));
2412 else
2413 global->name.label[0] = '\0';
2414 }
2415
2416 /* Load content */
2417 if (!task_load_content_internal(content_info, true, false, true))
2418 return false;
2419
2420 #ifdef HAVE_MENU
2421 /* Push quick menu onto menu stack */
2422 menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUICK_MENU, NULL);
2423 #endif
2424
2425 return true;
2426 }
2427
task_push_load_content_from_cli(const char * core_path,const char * fullpath,content_ctx_info_t * content_info,enum rarch_core_type type,retro_task_callback_t cb,void * user_data)2428 bool task_push_load_content_from_cli(
2429 const char *core_path,
2430 const char *fullpath,
2431 content_ctx_info_t *content_info,
2432 enum rarch_core_type type,
2433 retro_task_callback_t cb,
2434 void *user_data)
2435 {
2436 return task_load_content_internal(content_info, true, true, false);
2437 }
2438
task_push_start_builtin_core(content_ctx_info_t * content_info,enum rarch_core_type type,retro_task_callback_t cb,void * user_data)2439 bool task_push_start_builtin_core(
2440 content_ctx_info_t *content_info,
2441 enum rarch_core_type type,
2442 retro_task_callback_t cb,
2443 void *user_data)
2444 {
2445 /* Clear content path */
2446 path_clear(RARCH_PATH_CONTENT);
2447
2448 /* Preliminary stuff that has to be done before we
2449 * load the actual content. Can differ per mode. */
2450 retroarch_set_current_core_type(type, true);
2451
2452 /* Load content */
2453 if (!task_load_content_internal(content_info, true, false, false))
2454 {
2455 retroarch_menu_running();
2456 return false;
2457 }
2458
2459 /* Push quick menu onto menu stack */
2460 #ifdef HAVE_MENU
2461 menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUICK_MENU, NULL);
2462 #endif
2463
2464 return true;
2465 }
2466
task_push_load_content_with_core_from_menu(const char * fullpath,content_ctx_info_t * content_info,enum rarch_core_type type,retro_task_callback_t cb,void * user_data)2467 bool task_push_load_content_with_core_from_menu(
2468 const char *fullpath,
2469 content_ctx_info_t *content_info,
2470 enum rarch_core_type type,
2471 retro_task_callback_t cb,
2472 void *user_data)
2473 {
2474 path_set(RARCH_PATH_CONTENT, fullpath);
2475
2476 /* Load content */
2477 if (!task_load_content_internal(content_info, true, false, false))
2478 {
2479 retroarch_menu_running();
2480 return false;
2481 }
2482
2483 #ifdef HAVE_MENU
2484 /* Push quick menu onto menu stack */
2485 if (type != CORE_TYPE_DUMMY)
2486 menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUICK_MENU, NULL);
2487 #endif
2488
2489 return true;
2490 }
2491
task_push_load_content_with_current_core_from_companion_ui(const char * fullpath,content_ctx_info_t * content_info,enum rarch_core_type type,retro_task_callback_t cb,void * user_data)2492 bool task_push_load_content_with_current_core_from_companion_ui(
2493 const char *fullpath,
2494 content_ctx_info_t *content_info,
2495 enum rarch_core_type type,
2496 retro_task_callback_t cb,
2497 void *user_data)
2498 {
2499 content_state_t *p_content = content_state_get_ptr();
2500
2501 /* TODO/FIXME: Enable setting of these values
2502 * via function arguments */
2503 p_content->companion_ui_db_name[0] = '\0';
2504 p_content->companion_ui_crc32[0] = '\0';
2505
2506 /* Load content
2507 * > TODO/FIXME: Set loading_from_companion_ui 'false' for
2508 * now, until someone can implement the required higher
2509 * level functionality in 'win32_common.c' and 'ui_cocoa.m' */
2510 return task_push_load_content_with_core_from_menu(fullpath,
2511 content_info, type, cb, user_data);
2512 }
2513
2514
task_push_load_subsystem_with_core_from_menu(const char * fullpath,content_ctx_info_t * content_info,enum rarch_core_type type,retro_task_callback_t cb,void * user_data)2515 bool task_push_load_subsystem_with_core_from_menu(
2516 const char *fullpath,
2517 content_ctx_info_t *content_info,
2518 enum rarch_core_type type,
2519 retro_task_callback_t cb,
2520 void *user_data)
2521 {
2522 content_state_t *p_content = content_state_get_ptr();
2523
2524 p_content->pending_subsystem_init = true;
2525
2526 /* Load content */
2527 if (!task_load_content_internal(content_info, true, false, false))
2528 {
2529 retroarch_menu_running();
2530 return false;
2531 }
2532
2533 #ifdef HAVE_MENU
2534 /* Push quick menu onto menu stack */
2535 if (type != CORE_TYPE_DUMMY)
2536 menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUICK_MENU, NULL);
2537 #endif
2538
2539 return true;
2540 }
2541
content_get_status(bool * contentless,bool * is_inited)2542 void content_get_status(
2543 bool *contentless,
2544 bool *is_inited)
2545 {
2546 content_state_t *p_content = content_state_get_ptr();
2547
2548 *contentless = p_content->core_does_not_need_content;
2549 *is_inited = p_content->is_inited;
2550 }
2551
2552 /* Clears the pending subsystem rom buffer*/
content_clear_subsystem(void)2553 void content_clear_subsystem(void)
2554 {
2555 unsigned i;
2556 content_state_t *p_content = content_state_get_ptr();
2557
2558 p_content->pending_subsystem_rom_id = 0;
2559 p_content->pending_subsystem_init = false;
2560
2561 for (i = 0; i < RARCH_MAX_SUBSYSTEM_ROMS; i++)
2562 {
2563 if (p_content->pending_subsystem_roms[i])
2564 {
2565 free(p_content->pending_subsystem_roms[i]);
2566 p_content->pending_subsystem_roms[i] = NULL;
2567 }
2568 }
2569 }
2570
2571 /* Set the current subsystem*/
content_set_subsystem(unsigned idx)2572 void content_set_subsystem(unsigned idx)
2573 {
2574 const struct retro_subsystem_info *subsystem;
2575 rarch_system_info_t *system = runloop_get_system_info();
2576 content_state_t *p_content = content_state_get_ptr();
2577
2578 /* Core fully loaded, use the subsystem data */
2579 if (system->subsystem.data)
2580 subsystem = system->subsystem.data + idx;
2581 /* Core not loaded completely, use the data we peeked on load core */
2582 else
2583 subsystem = subsystem_data + idx;
2584
2585 p_content->pending_subsystem_id = idx;
2586
2587 if (subsystem && subsystem_current_count > 0)
2588 {
2589 strlcpy(p_content->pending_subsystem_ident,
2590 subsystem->ident, sizeof(p_content->pending_subsystem_ident));
2591
2592 p_content->pending_subsystem_rom_num = subsystem->num_roms;
2593 }
2594
2595 RARCH_LOG("[Subsystem]: Setting current subsystem to: %d(%s) Content amount: %d\n",
2596 p_content->pending_subsystem_id,
2597 p_content->pending_subsystem_ident,
2598 p_content->pending_subsystem_rom_num);
2599 }
2600
2601 /* Sets the subsystem by name */
content_set_subsystem_by_name(const char * subsystem_name)2602 bool content_set_subsystem_by_name(const char* subsystem_name)
2603 {
2604 rarch_system_info_t *system = runloop_get_system_info();
2605 unsigned i = 0;
2606 /* Core not loaded completely, use the data we peeked on load core */
2607 const struct retro_subsystem_info
2608 *subsystem = subsystem_data;
2609
2610 /* Core fully loaded, use the subsystem data */
2611 if (system->subsystem.data)
2612 subsystem = system->subsystem.data;
2613
2614 for (i = 0; i < subsystem_current_count; i++, subsystem++)
2615 {
2616 if (string_is_equal(subsystem_name, subsystem->ident))
2617 {
2618 content_set_subsystem(i);
2619 return true;
2620 }
2621 }
2622
2623 return false;
2624 }
2625
content_get_subsystem_friendly_name(const char * subsystem_name,char * subsystem_friendly_name,size_t len)2626 void content_get_subsystem_friendly_name(const char* subsystem_name, char* subsystem_friendly_name, size_t len)
2627 {
2628 rarch_system_info_t *system = runloop_get_system_info();
2629 unsigned i = 0;
2630 /* Core not loaded completely, use the data we peeked on load core */
2631 const struct retro_subsystem_info *subsystem = subsystem_data;
2632
2633 /* Core fully loaded, use the subsystem data */
2634 if (system->subsystem.data)
2635 subsystem = system->subsystem.data;
2636
2637 for (i = 0; i < subsystem_current_count; i++, subsystem++)
2638 {
2639 if (string_is_equal(subsystem_name, subsystem->ident))
2640 {
2641 strlcpy(subsystem_friendly_name, subsystem->desc, len);
2642 break;
2643 }
2644 }
2645
2646 return;
2647 }
2648
2649 /* Add a rom to the subsystem ROM buffer */
content_add_subsystem(const char * path)2650 void content_add_subsystem(const char* path)
2651 {
2652 content_state_t *p_content = content_state_get_ptr();
2653 size_t pending_size = PATH_MAX_LENGTH * sizeof(char);
2654 p_content->pending_subsystem_roms[p_content->pending_subsystem_rom_id] = (char*)malloc(pending_size);
2655
2656 strlcpy(p_content->pending_subsystem_roms[
2657 p_content->pending_subsystem_rom_id],
2658 path, pending_size);
2659 RARCH_LOG("[Subsystem]: Subsystem id: %d Subsystem ident:"
2660 " %s Content ID: %d, Content Path: %s\n",
2661 p_content->pending_subsystem_id,
2662 p_content->pending_subsystem_ident,
2663 p_content->pending_subsystem_rom_id,
2664 p_content->pending_subsystem_roms[
2665 p_content->pending_subsystem_rom_id]);
2666 p_content->pending_subsystem_rom_id++;
2667 }
2668
content_set_does_not_need_content(void)2669 void content_set_does_not_need_content(void)
2670 {
2671 content_state_t *p_content = content_state_get_ptr();
2672 p_content->core_does_not_need_content = true;
2673 }
2674
content_unset_does_not_need_content(void)2675 void content_unset_does_not_need_content(void)
2676 {
2677 content_state_t *p_content = content_state_get_ptr();
2678 p_content->core_does_not_need_content = false;
2679 }
2680
content_get_crc(void)2681 uint32_t content_get_crc(void)
2682 {
2683 content_state_t *p_content = content_state_get_ptr();
2684 if (p_content->pending_rom_crc)
2685 {
2686 p_content->pending_rom_crc = false;
2687 p_content->rom_crc = file_crc32(0,
2688 (const char*)p_content->pending_rom_crc_path);
2689 RARCH_LOG("[CONTENT LOAD]: CRC32: 0x%x .\n",
2690 (unsigned)p_content->rom_crc);
2691 }
2692 return p_content->rom_crc;
2693 }
2694
content_get_subsystem_rom(unsigned index)2695 char* content_get_subsystem_rom(unsigned index)
2696 {
2697 content_state_t *p_content = content_state_get_ptr();
2698 return p_content->pending_subsystem_roms[index];
2699 }
2700
content_is_inited(void)2701 bool content_is_inited(void)
2702 {
2703 content_state_t *p_content = content_state_get_ptr();
2704 return p_content->is_inited;
2705 }
2706
content_deinit(void)2707 void content_deinit(void)
2708 {
2709 content_state_t *p_content = content_state_get_ptr();
2710
2711 content_file_override_free(p_content);
2712 content_file_list_free(p_content->content_list);
2713
2714 p_content->content_list = NULL;
2715 p_content->rom_crc = 0;
2716 p_content->is_inited = false;
2717 p_content->core_does_not_need_content = false;
2718 p_content->pending_rom_crc = false;
2719 }
2720
2721 /* Set environment variables before a subsystem load */
content_set_subsystem_info(void)2722 void content_set_subsystem_info(void)
2723 {
2724 content_state_t *p_content = content_state_get_ptr();
2725 if (!p_content->pending_subsystem_init)
2726 return;
2727
2728 path_set(RARCH_PATH_SUBSYSTEM, p_content->pending_subsystem_ident);
2729 path_set_special(p_content->pending_subsystem_roms,
2730 p_content->pending_subsystem_rom_num);
2731 }
2732
2733 /* Initializes and loads a content file for the currently
2734 * selected libretro core. */
content_init(void)2735 bool content_init(void)
2736 {
2737 struct string_list content;
2738 content_information_ctx_t content_ctx;
2739 enum msg_hash_enums error_enum = MSG_UNKNOWN;
2740 content_state_t *p_content = content_state_get_ptr();
2741
2742 bool ret = true;
2743 char *error_string = NULL;
2744 global_t *global = global_get_ptr();
2745 rarch_system_info_t *sys_info = runloop_get_system_info();
2746 settings_t *settings = config_get_ptr();
2747 bool check_firmware_before_loading = settings->bools.check_firmware_before_loading;
2748 bool set_supports_no_game_enable = settings->bools.set_supports_no_game_enable;
2749 const char *path_dir_system = settings->paths.directory_system;
2750 const char *path_dir_cache = settings->paths.directory_cache;
2751
2752 content_file_list_free(p_content->content_list);
2753 p_content->content_list = NULL;
2754
2755 content_ctx.check_firmware_before_loading = check_firmware_before_loading;
2756 #ifdef HAVE_PATCH
2757 content_ctx.is_ips_pref = rarch_ctl(RARCH_CTL_IS_IPS_PREF, NULL);
2758 content_ctx.is_bps_pref = rarch_ctl(RARCH_CTL_IS_BPS_PREF, NULL);
2759 content_ctx.is_ups_pref = rarch_ctl(RARCH_CTL_IS_UPS_PREF, NULL);
2760 content_ctx.patch_is_blocked = rarch_ctl(RARCH_CTL_IS_PATCH_BLOCKED, NULL);
2761 #endif
2762 content_ctx.directory_system = NULL;
2763 content_ctx.directory_cache = NULL;
2764 content_ctx.name_ips = NULL;
2765 content_ctx.name_bps = NULL;
2766 content_ctx.name_ups = NULL;
2767 content_ctx.valid_extensions = NULL;
2768 content_ctx.block_extract = false;
2769 content_ctx.need_fullpath = false;
2770 content_ctx.set_supports_no_game_enable = false;
2771
2772 content_ctx.subsystem.data = NULL;
2773 content_ctx.subsystem.size = 0;
2774
2775 if (global)
2776 {
2777 if (!string_is_empty(global->name.ips))
2778 content_ctx.name_ips = strdup(global->name.ips);
2779 if (!string_is_empty(global->name.bps))
2780 content_ctx.name_bps = strdup(global->name.bps);
2781 if (!string_is_empty(global->name.ups))
2782 content_ctx.name_ups = strdup(global->name.ups);
2783 }
2784
2785 if (sys_info)
2786 {
2787 struct retro_system_info *system = runloop_get_libretro_system_info();
2788
2789 content_ctx.set_supports_no_game_enable = set_supports_no_game_enable;
2790
2791 if (!string_is_empty(path_dir_system))
2792 content_ctx.directory_system = strdup(path_dir_system);
2793 if (!string_is_empty(path_dir_cache))
2794 content_ctx.directory_cache = strdup(path_dir_cache);
2795 if (!string_is_empty(system->valid_extensions))
2796 content_ctx.valid_extensions = strdup(system->valid_extensions);
2797
2798 content_ctx.block_extract = system->block_extract;
2799 content_ctx.need_fullpath = system->need_fullpath;
2800
2801 content_ctx.subsystem.data = sys_info->subsystem.data;
2802 content_ctx.subsystem.size = sys_info->subsystem.size;
2803 }
2804
2805 p_content->is_inited = true;
2806
2807 if (string_list_initialize(&content))
2808 {
2809 if (!content_file_init(&content_ctx, p_content,
2810 &content, &error_enum, &error_string))
2811 {
2812 content_deinit();
2813 ret = false;
2814 }
2815 string_list_deinitialize(&content);
2816 }
2817
2818 if (content_ctx.name_ips)
2819 free(content_ctx.name_ips);
2820 if (content_ctx.name_bps)
2821 free(content_ctx.name_bps);
2822 if (content_ctx.name_ups)
2823 free(content_ctx.name_ups);
2824 if (content_ctx.directory_system)
2825 free(content_ctx.directory_system);
2826 if (content_ctx.directory_cache)
2827 free(content_ctx.directory_cache);
2828 if (content_ctx.valid_extensions)
2829 free(content_ctx.valid_extensions);
2830
2831 if (error_enum != MSG_UNKNOWN)
2832 {
2833 switch (error_enum)
2834 {
2835 case MSG_ERROR_LIBRETRO_CORE_REQUIRES_SPECIAL_CONTENT:
2836 case MSG_ERROR_LIBRETRO_CORE_REQUIRES_VFS:
2837 case MSG_FAILED_TO_LOAD_CONTENT:
2838 case MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT:
2839 RARCH_ERR("[CONTENT LOAD]: %s\n", msg_hash_to_str(error_enum));
2840 runloop_msg_queue_push(msg_hash_to_str(error_enum), 2, ret ? 1 : 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2841 break;
2842 case MSG_UNKNOWN:
2843 default:
2844 break;
2845 }
2846 }
2847
2848 if (error_string)
2849 {
2850 if (ret)
2851 {
2852 RARCH_LOG("[CONTENT LOAD]: %s\n", error_string);
2853 }
2854 else
2855 {
2856 RARCH_ERR("[CONTENT LOAD]: %s\n", error_string);
2857 }
2858 /* Do not flush the message queue here
2859 * > This allows any core-generated error messages
2860 * to propagate through to the frontend */
2861 runloop_msg_queue_push(error_string, 2, ret ? 1 : 180, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2862 free(error_string);
2863 }
2864
2865 return ret;
2866 }
2867