Use exception when load content fails. ui: graceful stop on fatal error

libretro: catch/detect fatal errors and shutdown
This commit is contained in:
Flyinghead 2021-08-03 10:05:09 +02:00
parent 2dd7717128
commit 951e70328f
13 changed files with 197 additions and 189 deletions

View File

@ -13,7 +13,7 @@ TA_context* read_frame(const char* file, u8* vram_ref = NULL);
void rend_set_fb_scale(float x,float y); void rend_set_fb_scale(float x,float y);
#ifdef TARGET_DISPFRAME #ifdef TARGET_DISPFRAME
void *dc_run(void*) void dc_run()
{ {
struct sigaction act, segv_oact; struct sigaction act, segv_oact;
memset(&act, 0, sizeof(act)); memset(&act, 0, sizeof(act));
@ -58,6 +58,5 @@ void *dc_run(void*)
os_DoEvents(); os_DoEvents();
} }
return nullptr;
} }
#endif #endif

View File

@ -42,8 +42,10 @@ extern int screen_width, screen_height;
std::atomic<bool> loading_canceled; std::atomic<bool> loading_canceled;
settings_t settings; settings_t settings;
static cThread emuThread(&dc_run, nullptr); static void *dc_run_thread(void *);
static cThread emuThread(&dc_run_thread, nullptr);
static bool initDone; static bool initDone;
static std::string lastError;
static s32 devicesInit() static s32 devicesInit()
{ {
@ -521,11 +523,27 @@ bool dc_is_running()
return sh4_cpu.IsCpuRunning(); return sh4_cpu.IsCpuRunning();
} }
#ifndef TARGET_DISPFRAME static void *dc_run_thread(void*)
void* dc_run(void*)
{ {
InitAudio(); InitAudio();
try {
dc_run();
} catch (const FlycastException& e) {
ERROR_LOG(COMMON, "%s", e.what());
sh4_cpu.Stop();
lastError = e.what();
}
TermAudio();
return nullptr;
}
#ifndef TARGET_DISPFRAME
void dc_run()
{
#if FEAT_SHREC != DYNAREC_NONE #if FEAT_SHREC != DYNAREC_NONE
if (config::DynarecEnabled) if (config::DynarecEnabled)
{ {
@ -557,10 +575,6 @@ void* dc_run(void*)
} }
} while (resetRequested); } while (resetRequested);
} }
TermAudio();
return NULL;
} }
#endif #endif
@ -583,8 +597,6 @@ void dc_term_emulator()
dc_term_game(); dc_term_game();
debugger::term(); debugger::term();
sh4_cpu.Term(); sh4_cpu.Term();
if (settings.platform.system != DC_PLATFORM_DREAMCAST)
naomi_cart_Close();
custom_texture.Terminate(); // lr: avoid deadlock on exit (win32) custom_texture.Terminate(); // lr: avoid deadlock on exit (win32)
devicesTerm(); devicesTerm();
mem_Term(); mem_Term();
@ -711,6 +723,13 @@ bool dc_loadstate(const void **data, u32 size)
return true; return true;
} }
std::string dc_get_last_error()
{
std::string error(lastError);
lastError.clear();
return error;
}
EventManager EventManager::Instance; EventManager EventManager::Instance;
void EventManager::registerEvent(Event event, Callback callback) void EventManager::registerEvent(Event event, Callback callback)

View File

@ -31,7 +31,7 @@ extern std::atomic<bool> loading_canceled;
int flycast_init(int argc, char* argv[]); int flycast_init(int argc, char* argv[]);
void dc_reset(bool hard); void dc_reset(bool hard);
void dc_init(); void dc_init();
void* dc_run(void*); void dc_run();
void dc_term(); void dc_term();
void dc_stop(); void dc_stop();
void dc_term_game(); void dc_term_game();
@ -50,6 +50,7 @@ void dc_cancel_load();
void dc_get_load_status(); void dc_get_load_status();
bool dc_is_running(); bool dc_is_running();
void dc_resize_renderer(); void dc_resize_renderer();
std::string dc_get_last_error();
enum class Event { enum class Event {
Start, Start,

View File

@ -1,25 +1,24 @@
#include "common.h" #include "common.h"
#include "stdclass.h"
#include "deps/chdpsr/cdipsr.h" #include "deps/chdpsr/cdipsr.h"
Disc* cdi_parse(const char* file) Disc* cdi_parse(const char* file)
{ {
// Only try to open .cdi files if (get_file_extension(file) != "cdi")
size_t len = strlen(file);
if (len > 4 && stricmp( &file[len - 4], ".cdi"))
return nullptr; return nullptr;
FILE *fsource = nowide::fopen(file, "rb"); FILE *fsource = nowide::fopen(file, "rb");
if (!fsource) if (fsource == nullptr)
return nullptr; throw FlycastException(std::string("Cannot open CDI file ") + file);
image_s image = { 0 }; image_s image = { 0 };
track_s track = { 0 }; track_s track = { 0 };
if (!CDI_init(fsource, &image, file)) if (!CDI_init(fsource, &image, file))
{ {
std::fclose(fsource); std::fclose(fsource);
return nullptr; throw FlycastException(std::string("Invalid CDI file ") + file);
} }
CDI_get_sessions(fsource,&image); CDI_get_sessions(fsource,&image);
@ -41,8 +40,6 @@ Disc* cdi_parse(const char* file)
image.header_position = std::ftell(fsource); image.header_position = std::ftell(fsource);
//printf("\nSession %d has %d track(s)\n",image.global_current_session,image.tracks);
if (image.tracks == 0) if (image.tracks == 0)
INFO_LOG(GDROM, "Open session"); INFO_LOG(GDROM, "Open session");
else else
@ -96,8 +93,6 @@ Disc* cdi_parse(const char* file)
if (track.mode==0) if (track.mode==0)
CD_DA=true; CD_DA=true;
t.ADDR=1;//hmm is that ok ? t.ADDR=1;//hmm is that ok ?
t.CTRL=track.mode==0?0:4; t.CTRL=track.mode==0?0:4;
@ -107,55 +102,30 @@ Disc* cdi_parse(const char* file)
rv->tracks.push_back(t); rv->tracks.push_back(t);
//printf("\n");
// if (track.pregap_length != 150) printf("Warning! This track seems to have a non-standard pregap...\n");
if (track.length < 0) if (track.length < 0)
WARN_LOG(GDROM, "Negative track size found. You must extract image with /pregap option"); WARN_LOG(GDROM, "Negative track size found. You must extract image with /pregap option");
//if (!opts.showinfo) std::fseek(fsource, track.position, SEEK_SET);
{
if (track.total_length < track.length + track.pregap_length) if (track.total_length < track.length + track.pregap_length)
{ {
WARN_LOG(GDROM, "This track seems truncated. Skipping..."); WARN_LOG(GDROM, "This track seems truncated. Skipping...");
std::fseek(fsource, track.position, SEEK_SET); // FIXME that can't be right
std::fseek(fsource, track.total_length, SEEK_CUR); std::fseek(fsource, track.total_length, SEEK_CUR);
track.position = std::ftell(fsource);
} }
else else
{ {
//printf("Track position: %lu\n",track.position + track.pregap_length * track.sector_size);
std::fseek(fsource, track.position, SEEK_SET);
// fseek(fsource, track->pregap_length * track->sector_size, SEEK_CUR);
// fseek(fsource, track->length * track->sector_size, SEEK_CUR);
std::fseek(fsource, track.total_length * track.sector_size, SEEK_CUR); std::fseek(fsource, track.total_length * track.sector_size, SEEK_CUR);
//savetrack(fsource, &image, &track, &opts, &flags);
track.position = std::ftell(fsource);
rv->EndFAD=track.start_lba +track.total_length; rv->EndFAD=track.start_lba +track.total_length;
// Generate cuesheet entries
//if (flags.create_cuesheet && !(track.mode == 2 && flags.do_convert)) // Do not generate input if converted (obsolete)
// savecuesheet(fcuesheet, &image, &track, &opts, &flags);
}
} }
track.position = std::ftell(fsource);
std::fseek(fsource, image.header_position, SEEK_SET); std::fseek(fsource, image.header_position, SEEK_SET);
// Close loops
image.remaining_tracks--; image.remaining_tracks--;
} }
//if (flags.create_cuesheet) fclose(fcuesheet);
} }
CDI_skip_next_session (fsource, &image); CDI_skip_next_session(fsource, &image);
image.remaining_sessions--; image.remaining_sessions--;
} }
@ -167,8 +137,6 @@ Disc* cdi_parse(const char* file)
rv->LeadOut.ADDR=0; rv->LeadOut.ADDR=0;
rv->LeadOut.CTRL=0; rv->LeadOut.CTRL=0;
return rv; return rv;
} }

View File

@ -1,9 +1,10 @@
#include "common.h" #include "common.h"
#include "stdclass.h"
#include <libchdr/chd.h> #include <libchdr/chd.h>
/* tracks are padded to a multiple of this many frames */ /* tracks are padded to a multiple of this many frames */
const uint32_t CD_TRACK_PADDING = 4; constexpr uint32_t CD_TRACK_PADDING = 4;
struct CHDDisc : Disc struct CHDDisc : Disc
{ {
@ -15,7 +16,7 @@ struct CHDDisc : Disc
u32 hunkbytes = 0; u32 hunkbytes = 0;
u32 sph = 0; u32 sph = 0;
bool TryOpen(const char* file); void tryOpen(const char* file);
~CHDDisc() override ~CHDDisc() override
{ {
@ -38,20 +39,21 @@ struct CHDTrack : TrackFile
CHDTrack(CHDDisc* disc, u32 StartFAD, s32 Offset, u32 fmt, bool swap_bytes) CHDTrack(CHDDisc* disc, u32 StartFAD, s32 Offset, u32 fmt, bool swap_bytes)
{ {
this->disc=disc; this->disc = disc;
this->StartFAD=StartFAD; this->StartFAD = StartFAD;
this->Offset = Offset; this->Offset = Offset;
this->fmt=fmt; this->fmt = fmt;
this->swap_bytes = swap_bytes; this->swap_bytes = swap_bytes;
} }
void Read(u32 FAD, u8* dst, SectorFormat* sector_type, u8* subcode, SubcodeFormat* subcode_type) override bool Read(u32 FAD, u8* dst, SectorFormat* sector_type, u8* subcode, SubcodeFormat* subcode_type) override
{ {
u32 fad_offs = FAD + Offset; u32 fad_offs = FAD + Offset;
u32 hunk=(fad_offs)/disc->sph; u32 hunk=(fad_offs)/disc->sph;
if (disc->old_hunk!=hunk) if (disc->old_hunk!=hunk)
{ {
chd_read(disc->chd,hunk,disc->hunk_mem); //CHDERR_NONE if (chd_read(disc->chd,hunk,disc->hunk_mem) != CHDERR_NONE)
return false;
disc->old_hunk = hunk; disc->old_hunk = hunk;
} }
@ -73,24 +75,21 @@ struct CHDTrack : TrackFile
//While space is reserved for it, the images contain no actual subcodes //While space is reserved for it, the images contain no actual subcodes
//memcpy(subcode,disc->hunk_mem+hunk_ofs*(2352+96)+2352,96); //memcpy(subcode,disc->hunk_mem+hunk_ofs*(2352+96)+2352,96);
*subcode_type=SUBFMT_NONE; *subcode_type=SUBFMT_NONE;
return true;
} }
}; };
bool CHDDisc::TryOpen(const char* file) void CHDDisc::tryOpen(const char* file)
{ {
fp = nowide::fopen(file, "rb"); fp = nowide::fopen(file, "rb");
if (fp == nullptr) if (fp == nullptr)
{ throw FlycastException(std::string("Cannot open CHD file ") + file);
INFO_LOG(GDROM, "chd: fopen failed for file %s: %d", file, errno);
return false;
}
chd_error err = chd_open_file(fp, CHD_OPEN_READ, 0, &chd); chd_error err = chd_open_file(fp, CHD_OPEN_READ, 0, &chd);
if (err != CHDERR_NONE) if (err != CHDERR_NONE)
{ throw FlycastException(std::string("Invalid CHD file ") + file);
INFO_LOG(GDROM, "chd: chd_open_file failed for file %s: %d", file, err);
return false;
}
INFO_LOG(GDROM, "chd: parsing file %s", file); INFO_LOG(GDROM, "chd: parsing file %s", file);
@ -102,11 +101,8 @@ bool CHDDisc::TryOpen(const char* file)
sph = hunkbytes/(2352+96); sph = hunkbytes/(2352+96);
if (hunkbytes%(2352+96)!=0) if (hunkbytes % (2352 + 96) != 0)
{ throw FlycastException(std::string("Invalid hunkbytes for CHD file ") + file);
INFO_LOG(GDROM, "chd: hunkbytes is invalid, %d\n",hunkbytes);
return false;
}
u32 tag; u32 tag;
u8 flags; u8 flags;
@ -156,15 +152,13 @@ bool CHDDisc::TryOpen(const char* file)
|| pregap != 0 || pregap != 0
|| postgap != 0) || postgap != 0)
{ {
INFO_LOG(GDROM, "chd: track type %s is not supported", type); throw FlycastException((std::string("chd: track type ") + type) + " is not supported");
return false;
} }
DEBUG_LOG(GDROM, "%s", temp); DEBUG_LOG(GDROM, "%s", temp);
Track t; Track t;
t.StartFAD = total_frames; t.StartFAD = total_frames;
total_frames += frames; total_frames += frames;
t.EndFAD = total_frames - 1; t.EndFAD = total_frames - 1;
t.ADDR = 0;
t.CTRL = strcmp(type,"AUDIO") == 0 ? 0 : 4; t.CTRL = strcmp(type,"AUDIO") == 0 ? 0 : 4;
t.file = new CHDTrack(this, t.StartFAD, Offset - t.StartFAD, strcmp(type, "MODE1") ? 2352 : 2048, t.file = new CHDTrack(this, t.StartFAD, Offset - t.StartFAD, strcmp(type, "MODE1") ? 2352 : 2048,
@ -182,25 +176,21 @@ bool CHDDisc::TryOpen(const char* file)
WARN_LOG(GDROM, "WARNING: chd: Total frames is wrong: %u frames (549300 expected) in %zu tracks", total_frames, tracks.size()); WARN_LOG(GDROM, "WARNING: chd: Total frames is wrong: %u frames (549300 expected) in %zu tracks", total_frames, tracks.size());
FillGDSession(); FillGDSession();
return true;
} }
Disc* chd_parse(const char* file) Disc* chd_parse(const char* file)
{ {
// Only try to open .chd files if (get_file_extension(file) != "chd")
size_t len = strlen(file);
if (len > 4 && stricmp( &file[len - 4], ".chd"))
return nullptr; return nullptr;
CHDDisc* rv = new CHDDisc(); CHDDisc* rv = new CHDDisc();
if (rv->TryOpen(file)) try {
rv->tryOpen(file);
return rv; return rv;
else } catch (...) {
{
delete rv; delete rv;
return 0; throw;
} }
} }

View File

@ -87,37 +87,29 @@ struct Session
struct TrackFile struct TrackFile
{ {
virtual void Read(u32 FAD,u8* dst,SectorFormat* sector_type,u8* subcode,SubcodeFormat* subcode_type)=0; virtual bool Read(u32 FAD, u8 *dst, SectorFormat *sector_type, u8 *subcode, SubcodeFormat *subcode_type) = 0;
virtual ~TrackFile() = default;; virtual ~TrackFile() = default;
}; };
struct Track struct Track
{ {
TrackFile* file; //handler for actual IO TrackFile* file = nullptr; // handler for actual IO
u32 StartFAD; //Start FAD u32 StartFAD = 0; // Start FAD
u32 EndFAD; //End FAD u32 EndFAD = 0; // End FAD
u8 CTRL; u8 CTRL = 0;
u8 ADDR; u8 ADDR = 0;
Track() bool Read(u32 FAD, u8 *dst, SectorFormat *sector_type, u8 *subcode, SubcodeFormat *subcode_type)
{ {
file = 0; if (FAD >= StartFAD && (FAD <= EndFAD || EndFAD == 0) && file != nullptr)
StartFAD = 0; return file->Read(FAD, dst, sector_type, subcode, subcode_type);
EndFAD = 0;
CTRL = 0;
ADDR = 0;
}
bool Read(u32 FAD,u8* dst,SectorFormat* sector_type,u8* subcode,SubcodeFormat* subcode_type)
{
if (FAD>=StartFAD && (FAD<=EndFAD || EndFAD==0) && file)
{
file->Read(FAD,dst,sector_type,subcode,subcode_type);
return true;
}
else else
return false; return false;
} }
void Destroy() { delete file; file=0; } void Destroy() {
delete file;
file = nullptr;
}
}; };
struct Disc struct Disc
@ -196,7 +188,7 @@ struct Disc
} }
else else
{ {
INFO_LOG(GDROM, "Sector Read miss FAD: %d", FAD); WARN_LOG(GDROM, "Sector Read miss FAD: %d", FAD);
} }
dst+=fmt; dst+=fmt;
FAD++; FAD++;
@ -261,18 +253,16 @@ struct RawTrackFile : TrackFile
FILE *file; FILE *file;
s32 offset; s32 offset;
u32 fmt; u32 fmt;
bool cleanup;
RawTrackFile(FILE *file, u32 file_offs, u32 first_fad, u32 secfmt) RawTrackFile(FILE *file, u32 file_offs, u32 first_fad, u32 secfmt)
{ {
verify(file!=0); verify(file != nullptr);
this->file=file; this->file = file;
this->offset=file_offs-first_fad*secfmt; this->offset = file_offs - first_fad * secfmt;
this->fmt=secfmt; this->fmt = secfmt;
this->cleanup=true;
} }
void Read(u32 FAD,u8* dst,SectorFormat* sector_type,u8* subcode,SubcodeFormat* subcode_type) override bool Read(u32 FAD,u8* dst,SectorFormat* sector_type,u8* subcode,SubcodeFormat* subcode_type) override
{ {
//for now hackish //for now hackish
if (fmt==2352) if (fmt==2352)
@ -290,11 +280,15 @@ struct RawTrackFile : TrackFile
std::fseek(file, offset + FAD * fmt, SEEK_SET); std::fseek(file, offset + FAD * fmt, SEEK_SET);
if (std::fread(dst, 1, fmt, file) != fmt) if (std::fread(dst, 1, fmt, file) != fmt)
{
WARN_LOG(GDROM, "Failed or truncated GD-Rom read"); WARN_LOG(GDROM, "Failed or truncated GD-Rom read");
return false;
} }
return true;
}
~RawTrackFile() override ~RawTrackFile() override
{ {
if (cleanup && file)
std::fclose(file); std::fclose(file);
} }
}; };

View File

@ -18,6 +18,7 @@
*/ */
#include "common.h" #include "common.h"
#include "stdclass.h"
#include <sstream> #include <sstream>
extern std::string OS_dirname(std::string file); extern std::string OS_dirname(std::string file);
@ -46,15 +47,13 @@ static u32 getSectorSize(const std::string& type) {
Disc* cue_parse(const char* file) Disc* cue_parse(const char* file)
{ {
// Only try to open .cue files if (get_file_extension(file) != "cue")
size_t len = strlen(file);
if (len > 4 && stricmp( &file[len - 4], ".cue"))
return nullptr; return nullptr;
FILE *fsource = nowide::fopen(file, "rb"); FILE *fsource = nowide::fopen(file, "rb");
if (fsource == nullptr) if (fsource == nullptr)
return nullptr; throw FlycastException(std::string("Cannot open CUE file ") + file);
size_t cue_len = flycast::fsize(fsource); size_t cue_len = flycast::fsize(fsource);
@ -62,9 +61,8 @@ Disc* cue_parse(const char* file)
if (cue_len >= sizeof(cue_data)) if (cue_len >= sizeof(cue_data))
{ {
WARN_LOG(GDROM, "CUE parse error: CUE file too big");
std::fclose(fsource); std::fclose(fsource);
return nullptr; throw FlycastException("CUE parse error: CUE file too big");
} }
if (std::fread(cue_data, 1, cue_len, fsource) != cue_len) if (std::fread(cue_data, 1, cue_len, fsource) != cue_len)
@ -163,24 +161,21 @@ Disc* cue_parse(const char* file)
if (index_num == 1) if (index_num == 1)
{ {
Track t; Track t;
t.ADDR = 0;
t.StartFAD = current_fad; t.StartFAD = current_fad;
t.CTRL = (track_type == "AUDIO" || track_type == "CDG") ? 0 : 4; t.CTRL = (track_type == "AUDIO" || track_type == "CDG") ? 0 : 4;
std::string path = basepath + normalize_path_separator(track_filename); std::string path = basepath + normalize_path_separator(track_filename);
FILE *track_file = nowide::fopen(path.c_str(), "rb"); FILE *track_file = nowide::fopen(path.c_str(), "rb");
if (track_file == nullptr) if (track_file == nullptr)
{ {
WARN_LOG(GDROM, "CUE file: cannot open track %d: %s", track_number, path.c_str());
delete disc; delete disc;
return nullptr; throw FlycastException("CUE file: cannot open track " + path);
} }
u32 sector_size = getSectorSize(track_type); u32 sector_size = getSectorSize(track_type);
if (sector_size == 0) if (sector_size == 0)
{ {
WARN_LOG(GDROM, "CUE file: track %d has unknown sector type: %s", track_number, track_type.c_str());
std::fclose(track_file); std::fclose(track_file);
delete disc; delete disc;
return nullptr; throw FlycastException("CUE file: track has unknown sector type: " + track_type);
} }
if (flycast::fsize(track_file) % sector_size != 0) if (flycast::fsize(track_file) % sector_size != 0)
WARN_LOG(GDROM, "Warning: Size of track %s is not multiple of sector size %d", track_filename.c_str(), sector_size); WARN_LOG(GDROM, "Warning: Size of track %s is not multiple of sector size %d", track_filename.c_str(), sector_size);
@ -199,9 +194,8 @@ Disc* cue_parse(const char* file)
} }
if (disc->tracks.empty()) if (disc->tracks.empty())
{ {
WARN_LOG(GDROM, "CUE parse error: failed to parse or invalid file with 0 tracks");
delete disc; delete disc;
return nullptr; throw FlycastException("CUE parse error: failed to parse or invalid file with 0 tracks");
} }
if (session_number == 0) if (session_number == 0)

View File

@ -1,4 +1,5 @@
#include "common.h" #include "common.h"
#include "stdclass.h"
#include <algorithm> #include <algorithm>
#include <sstream> #include <sstream>
@ -62,8 +63,8 @@ namespace {
Disc* load_gdi(const char* file) Disc* load_gdi(const char* file)
{ {
FILE *t = nowide::fopen(file, "rb"); FILE *t = nowide::fopen(file, "rb");
if (!t) if (t == nullptr)
return nullptr; throw FlycastException(std::string("Cannot open GDI file ") + file);
size_t gdi_len = flycast::fsize(t); size_t gdi_len = flycast::fsize(t);
@ -71,9 +72,8 @@ Disc* load_gdi(const char* file)
if (gdi_len >= sizeof(gdi_data)) if (gdi_len >= sizeof(gdi_data))
{ {
WARN_LOG(GDROM, "GDI: file too big");
std::fclose(t); std::fclose(t);
return nullptr; throw FlycastException("GDI file too big");
} }
if (std::fread(gdi_data, 1, gdi_len, t) != gdi_len) if (std::fread(gdi_data, 1, gdi_len, t) != gdi_len)
@ -85,10 +85,8 @@ Disc* load_gdi(const char* file)
u32 iso_tc = 0; u32 iso_tc = 0;
gdi >> iso_tc; gdi >> iso_tc;
if (iso_tc == 0) if (iso_tc == 0)
{ throw FlycastException("GDI: empty or invalid GDI file");
WARN_LOG(GDROM, "GDI: empty or invalid GDI file");
return nullptr;
}
INFO_LOG(GDROM, "GDI : %d tracks", iso_tc); INFO_LOG(GDROM, "GDI : %d tracks", iso_tc);
std::string basepath = OS_dirname(file); std::string basepath = OS_dirname(file);
@ -134,16 +132,19 @@ Disc* load_gdi(const char* file)
DEBUG_LOG(GDROM, "file[%d] \"%s\": FAD:%d, CTRL:%d, SSIZE:%d, OFFSET:%d", TRACK, track_filename.c_str(), FADS, CTRL, SSIZE, OFFSET); DEBUG_LOG(GDROM, "file[%d] \"%s\": FAD:%d, CTRL:%d, SSIZE:%d, OFFSET:%d", TRACK, track_filename.c_str(), FADS, CTRL, SSIZE, OFFSET);
Track t; Track t;
t.ADDR=0; t.StartFAD = FADS + 150;
t.StartFAD=FADS+150;
t.EndFAD=0; //fill it in
t.file=0;
t.CTRL = CTRL; t.CTRL = CTRL;
if (SSIZE!=0) if (SSIZE!=0)
{ {
std::string path = basepath + normalize_path_separator(track_filename); std::string path = basepath + normalize_path_separator(track_filename);
t.file = new RawTrackFile(nowide::fopen(path.c_str(), "rb"), OFFSET, t.StartFAD,SSIZE); FILE *file = nowide::fopen(path.c_str(), "rb");
if (file == nullptr)
{
delete disc;
throw FlycastException("GDI file: Cannot open track " + path);
}
t.file = new RawTrackFile(file, OFFSET, t.StartFAD, SSIZE);
} }
if (!disc->tracks.empty()) if (!disc->tracks.empty())
disc->tracks.back().EndFAD = t.StartFAD - 1; disc->tracks.back().EndFAD = t.StartFAD - 1;
@ -158,13 +159,8 @@ Disc* load_gdi(const char* file)
Disc* gdi_parse(const char* file) Disc* gdi_parse(const char* file)
{ {
size_t len=strlen(file); if (get_file_extension(file) != "gdi")
if (len>4) return nullptr;
{
if (stricmp( &file[len-4],".gdi")==0)
{
return load_gdi(file); return load_gdi(file);
}
}
return 0;
} }

View File

@ -394,6 +394,7 @@ static void reios_sys_misc()
case 1: // Exit to BIOS menu case 1: // Exit to BIOS menu
WARN_LOG(REIOS, "SYS_MISC 1"); WARN_LOG(REIOS, "SYS_MISC 1");
throw FlycastException("Reboot to BIOS");
break; break;
case 2: // check disk case 2: // check disk
@ -645,9 +646,8 @@ static void reios_boot()
std::string extension = get_file_extension(settings.imgread.ImagePath); std::string extension = get_file_extension(settings.imgread.ImagePath);
if (extension == "elf") if (extension == "elf")
{ {
if (!reios_loadElf(settings.imgread.ImagePath)) { if (!reios_loadElf(settings.imgread.ImagePath))
msgboxf("Failed to open %s", MBX_ICONERROR, settings.imgread.ImagePath); throw FlycastException(std::string("Failed to open ELF ") + settings.imgread.ImagePath);
}
reios_setup_state(0x8C010000); reios_setup_state(0x8C010000);
} }
else { else {
@ -656,7 +656,7 @@ static void reios_boot()
char bootfile[sizeof(ip_meta.boot_filename) + 1] = {0}; char bootfile[sizeof(ip_meta.boot_filename) + 1] = {0};
memcpy(bootfile, ip_meta.boot_filename, sizeof(ip_meta.boot_filename)); memcpy(bootfile, ip_meta.boot_filename, sizeof(ip_meta.boot_filename));
if (bootfile[0] == '\0' || !reios_locate_bootfile(bootfile)) if (bootfile[0] == '\0' || !reios_locate_bootfile(bootfile))
msgboxf("Failed to locate bootfile %s", MBX_ICONERROR, bootfile); throw FlycastException(std::string("Failed to locate bootfile ") + bootfile);
reios_setup_state(0xac008300); reios_setup_state(0xac008300);
} }
else { else {
@ -668,14 +668,14 @@ static void reios_boot()
} }
u32 data_size = 4; u32 data_size = 4;
u32* sz = (u32*)CurrentCartridge->GetPtr(0x368, data_size); u32* sz = (u32*)CurrentCartridge->GetPtr(0x368, data_size);
if (!sz || data_size != 4) { if (sz == nullptr || data_size != 4)
msgboxf("Naomi boot failure", MBX_ICONERROR); throw FlycastException("Naomi boot failure");
}
const u32 size = *sz; const u32 size = *sz;
data_size = 1; data_size = 1;
verify(size < RAM_SIZE && CurrentCartridge->GetPtr(size - 1, data_size) && "Invalid cart size"); if (size > RAM_SIZE || CurrentCartridge->GetPtr(size - 1, data_size) == nullptr)
throw FlycastException("Invalid cart size");
data_size = size; data_size = size;
WriteMemBlock_nommu_ptr(0x0c020000, (u32*)CurrentCartridge->GetPtr(0, data_size), size); WriteMemBlock_nommu_ptr(0x0c020000, (u32*)CurrentCartridge->GetPtr(0, data_size), size);

View File

@ -432,6 +432,26 @@ static void gui_start_game(const std::string& path)
dc_load_game(path.empty() ? NULL : path_copy.c_str()); dc_load_game(path.empty() ? NULL : path_copy.c_str());
} }
void gui_stop_game(const std::string& message)
{
if (!commandLineStart)
{
// Exit to main menu
dc_term_game();
gui_state = GuiState::Main;
game_started = false;
settings.imgread.ImagePath[0] = '\0';
reset_vmus();
if (!message.empty())
error_msg = "Flycast has stopped.\n\n" + message;
}
else
{
// Exit emulator
dc_exit();
}
}
static void gui_display_commands() static void gui_display_commands()
{ {
if (dc_is_running()) if (dc_is_running())
@ -515,20 +535,7 @@ static void gui_display_commands()
if (ImGui::Button("Exit", ImVec2(300 * scaling + ImGui::GetStyle().ColumnsMinSpacing + ImGui::GetStyle().FramePadding.x * 2 - 1, if (ImGui::Button("Exit", ImVec2(300 * scaling + ImGui::GetStyle().ColumnsMinSpacing + ImGui::GetStyle().FramePadding.x * 2 - 1,
50 * scaling))) 50 * scaling)))
{ {
if (!commandLineStart) gui_stop_game();
{
// Exit to main menu
dc_term_game();
gui_state = GuiState::Main;
game_started = false;
settings.imgread.ImagePath[0] = '\0';
reset_vmus();
}
else
{
// Exit emulator
dc_exit();
}
} }
ImGui::End(); ImGui::End();
@ -909,6 +916,9 @@ static void error_popup()
{ {
if (!error_msg.empty()) if (!error_msg.empty())
{ {
ImVec2 padding = ImVec2(20 * scaling, 20 * scaling);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, padding);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, padding);
ImGui::OpenPopup("Error"); ImGui::OpenPopup("Error");
if (ImGui::BeginPopupModal("Error", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove)) if (ImGui::BeginPopupModal("Error", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove))
{ {
@ -924,8 +934,11 @@ static void error_popup()
} }
ImGui::SetItemDefaultFocus(); ImGui::SetItemDefaultFocus();
ImGui::PopStyleVar(); ImGui::PopStyleVar();
ImGui::PopTextWrapPos();
ImGui::EndPopup(); ImGui::EndPopup();
} }
ImGui::PopStyleVar();
ImGui::PopStyleVar();
} }
} }
@ -1918,8 +1931,12 @@ static void gui_display_content()
if (gui_state == GuiState::SelectDisk) if (gui_state == GuiState::SelectDisk)
{ {
strcpy(settings.imgread.ImagePath, game.path.c_str()); strcpy(settings.imgread.ImagePath, game.path.c_str());
try {
DiscSwap(); DiscSwap();
gui_state = GuiState::Closed; gui_state = GuiState::Closed;
} catch (const FlycastException& e) {
error_msg = e.what();
}
} }
else else
{ {

View File

@ -36,6 +36,7 @@ void gui_set_mouse_position(int x, int y);
void gui_set_mouse_button(int button, bool pressed); void gui_set_mouse_button(int button, bool pressed);
void gui_set_mouse_wheel(float delta); void gui_set_mouse_wheel(float delta);
void gui_set_insets(int left, int right, int top, int bottom); void gui_set_insets(int left, int right, int top, int bottom);
void gui_stop_game(const std::string& message = "");
extern int screen_dpi; extern int screen_dpi;
extern float scaling; extern float scaling;

View File

@ -49,6 +49,11 @@ bool mainui_rend_frame()
if (!rend_single_frame(mainui_enabled)) if (!rend_single_frame(mainui_enabled))
{ {
UpdateInputState(); UpdateInputState();
if (!dc_is_running())
{
dc_stop();
gui_stop_game(dc_get_last_error());
}
return false; return false;
} }
} }

View File

@ -845,12 +845,26 @@ void retro_run()
// Render // Render
is_dupe = true; is_dupe = true;
for (int i = 0; i < 5 && is_dupe; i++) for (int i = 0; i < 5 && is_dupe; i++)
{
is_dupe = !rend_single_frame(true); is_dupe = !rend_single_frame(true);
if (!dc_is_running()) {
std::string error = dc_get_last_error();
if (!error.empty())
gui_display_notification(error.c_str(), 5000);
environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, NULL);
}
}
} }
else else
{ {
startTime = sh4_sched_now64(); startTime = sh4_sched_now64();
dc_run(nullptr); try {
dc_run();
} catch (const FlycastException& e) {
ERROR_LOG(COMMON, "%s", e.what());
gui_display_notification(e.what(), 5000);
environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, NULL);
}
} }
if (config::RendererType.isOpenGL()) if (config::RendererType.isOpenGL())
@ -870,7 +884,7 @@ static bool loadGame(const char *path)
} catch (const FlycastException& e) { } catch (const FlycastException& e) {
ERROR_LOG(BOOT, "%s", e.what()); ERROR_LOG(BOOT, "%s", e.what());
mute_messages = false; mute_messages = false;
gui_display_notification(e.what(), 2000); gui_display_notification(e.what(), 5000);
return false; return false;
} }
mute_messages = false; mute_messages = false;
@ -2751,7 +2765,12 @@ static bool retro_set_eject_state(bool ejected)
} }
else else
{ {
try {
return DiscSwap(); return DiscSwap();
} catch (const FlycastException& e) {
ERROR_LOG(GDROM, "%s", e.what());
return false;
}
} }
} }
@ -2779,8 +2798,13 @@ static bool retro_set_image_index(unsigned index)
if (disc_tray_open) if (disc_tray_open)
return true; return true;
else
try {
return DiscSwap(); return DiscSwap();
} catch (const FlycastException& e) {
ERROR_LOG(GDROM, "%s", e.what());
return false;
}
} }
static unsigned retro_get_num_images() static unsigned retro_get_num_images()