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