diff --git a/core/cfg/cl.cpp b/core/cfg/cl.cpp
index cb36627a8..7382cf662 100644
--- a/core/cfg/cl.cpp
+++ b/core/cfg/cl.cpp
@@ -133,7 +133,8 @@ bool ParseCommandLine(int argc,wchar* argv[])
if (extension
&& (stricmp(extension, ".cdi") == 0 || stricmp(extension, ".chd") == 0
- || stricmp(extension, ".gdi") == 0 || stricmp(extension, ".lst") == 0))
+ || stricmp(extension, ".gdi") == 0 || stricmp(extension, ".lst") == 0
+ || stricmp(extension, ".cue") == 0))
{
printf("Using '%s' as cd image\n", *arg);
cfgSetVirtual("config", "image", *arg);
diff --git a/core/imgread/common.cpp b/core/imgread/common.cpp
index 268cbd542..ca108cc0e 100644
--- a/core/imgread/common.cpp
+++ b/core/imgread/common.cpp
@@ -3,6 +3,7 @@
Disc* chd_parse(const wchar* file);
Disc* gdi_parse(const wchar* file);
Disc* cdi_parse(const wchar* file);
+Disc* cue_parse(const wchar* file);
#if HOST_OS==OS_WINDOWS
Disc* ioctl_parse(const wchar* file);
#endif
@@ -15,6 +16,7 @@ Disc*(*drivers[])(const wchar* path)=
chd_parse,
gdi_parse,
cdi_parse,
+ cue_parse,
#if HOST_OS==OS_WINDOWS
ioctl_parse,
#endif
diff --git a/core/imgread/cue.cpp b/core/imgread/cue.cpp
new file mode 100644
index 000000000..6afa63c72
--- /dev/null
+++ b/core/imgread/cue.cpp
@@ -0,0 +1,177 @@
+/*
+ Copyright 2019 flyinghead
+
+ This file is part of reicast.
+
+ reicast is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ reicast is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with reicast. If not, see .
+ */
+
+#include
+#include "types.h"
+#include "common.h"
+
+extern string OS_dirname(string file);
+extern string normalize_path_separator(string path);
+
+static u32 getSectorSize(const string& type) {
+ if (type == "AUDIO")
+ return 2352; // PCM Audio
+ else if (type == "CDG")
+ return 2352; // Karaoke cd+g
+ else if (type == "MODE1/2048")
+ return 2048; // CDROM Mode1 Data (cooked)
+ else if (type == "MODE1/2352")
+ return 2352; // CDROM Mode1 Data (raw)
+ else if (type == "MODE2/2336")
+ return 2336; // CDROM XA Mode2 Data
+ else if (type == "MODE2/2352")
+ return 2352; // CDROM XA Mode2 Data
+ else if (type == "CDI/2336")
+ return 2336; // CDI Mode2 Data
+ else if (type == "CDI/2352")
+ return 2352; // CDI Mode2 Data
+ else
+ return 0;
+}
+
+Disc* cue_parse(const wchar* file)
+{
+ core_file* fsource = core_fopen(file);
+
+ if (fsource == NULL)
+ return NULL;
+
+ Disc* disc = new Disc();
+
+ size_t cue_len = core_fsize(fsource);
+
+ char cue_data[8193] = { 0 };
+
+ if (cue_len >= sizeof(cue_data))
+ {
+ printf("CUE parse error: CUE file too big\n");
+ core_fclose(fsource);
+ return NULL;
+ }
+
+ core_fread(fsource, cue_data, cue_len);
+ core_fclose(fsource);
+
+ istringstream cuesheet(cue_data);
+
+ string basepath = OS_dirname(file);
+
+ bool high_density_area = false;
+ u32 current_fad = 150;
+ string track_filename;
+ u32 track_number = -1;
+ string track_type;
+
+ while (!cuesheet.eof())
+ {
+ string token;
+ cuesheet >> token;
+
+ if (token == "REM")
+ {
+ cuesheet >> token;
+ if (token == "HIGH-DENSITY")
+ {
+ high_density_area = true;
+ current_fad = 45000 + 150;
+ }
+ else if (token != "SINGLE-DENSITY")
+ printf("CUE parse error: unrecognized REM token %s. Expected SINGLE-DENSITY or HIGH-DENSITY\n", token.c_str());
+ cuesheet >> token;
+ if (token != "AREA")
+ printf("CUE parse error: unrecognized REM token %s. Expected AREA\n", token.c_str());
+ }
+ else if (token == "FILE")
+ {
+ char last;
+
+ do {
+ cuesheet >> last;
+ } while (isspace(last));
+
+ if (last == '"')
+ {
+ cuesheet >> std::noskipws;
+ for (;;) {
+ cuesheet >> last;
+ if (last == '"')
+ break;
+ track_filename += last;
+ }
+ cuesheet >> std::skipws;
+ }
+ else
+ {
+ cuesheet >> track_filename;
+ track_filename = last + track_filename;
+ }
+ cuesheet >> token; // BINARY
+ if (token != "BINARY")
+ printf("CUE parse error: unrecognized FILE token %s. Expected BINARY\n", token.c_str());
+ }
+ else if (token == "TRACK")
+ {
+ cuesheet >> track_number;
+ cuesheet >> track_type;
+ }
+ else if (token == "INDEX")
+ {
+ u32 index_num;
+ cuesheet >> index_num;
+ if (index_num == 1)
+ {
+ string offset;
+ cuesheet >> offset;
+
+ Track t;
+ t.ADDR = 0;
+ t.StartFAD = current_fad;
+ t.EndFAD = 0;
+ string path = basepath + normalize_path_separator(track_filename);
+ core_file* track_file = core_fopen(path.c_str());
+ if (track_file == NULL)
+ {
+ printf("CUE file: cannot open track %d: %s\n", track_number, path.c_str());
+ return NULL;
+ }
+ u32 sector_size = getSectorSize(track_type);
+ if (core_fsize(track_file) % sector_size != 0)
+ printf("Warning: Size of track %s is not multiple of sector size %d\n", track_filename.c_str(), sector_size);
+ current_fad = t.StartFAD + (u32)core_fsize(track_file) / sector_size;
+
+ printf("file[%d] \"%s\": StartFAD:%d, sector_size:%d file_size:%d\n", disc->tracks.size(),
+ track_filename.c_str(), t.StartFAD, sector_size, (u32)core_fsize(track_file));
+
+ t.file = new RawTrackFile(track_file, 0, t.StartFAD, sector_size);
+ disc->tracks.push_back(t);
+
+ track_number = -1;
+ track_type.clear();
+ track_filename.clear();
+ }
+ else
+ current_fad += 150;
+ }
+
+ }
+
+ disc->FillGDSession();
+
+ return disc;
+}
diff --git a/shell/android-studio/reicast/src/dreamcast/AndroidManifest.xml b/shell/android-studio/reicast/src/dreamcast/AndroidManifest.xml
index e595388f9..2043b0397 100644
--- a/shell/android-studio/reicast/src/dreamcast/AndroidManifest.xml
+++ b/shell/android-studio/reicast/src/dreamcast/AndroidManifest.xml
@@ -40,6 +40,16 @@
android:mimeType="*/*"
android:pathPattern=".*\\.cdi"
android:scheme="file" />
+
+
diff --git a/shell/apple/emulator-ios/emulator/PathsViewController.m b/shell/apple/emulator-ios/emulator/PathsViewController.m
index 2e959bbf0..31cc6fa4b 100644
--- a/shell/apple/emulator-ios/emulator/PathsViewController.m
+++ b/shell/apple/emulator-ios/emulator/PathsViewController.m
@@ -50,7 +50,9 @@
self.diskImages = [[NSMutableArray alloc] init];
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[self documents].path error:NULL];
- NSPredicate *diskPredicate = [NSPredicate predicateWithFormat:@"self ENDSWITH '.chd' || self ENDSWITH '.gdi' || self ENDSWITH '.cdi' || self ENDSWITH '.CHD' || self ENDSWITH '.GDI' || self ENDSWITH '.CDI'"];
+ NSPredicate *diskPredicate = [NSPredicate predicateWithFormat:@"self ENDSWITH '.chd' || self ENDSWITH '.gdi'
+ || self ENDSWITH '.cdi' || self ENDSWITH '.cue' || self ENDSWITH '.CHD' || self ENDSWITH '.GDI'
+ || self ENDSWITH '.CDI' || self ENDSWITH '.CUE'"];
self.diskImages = [NSMutableArray arrayWithArray:[files filteredArrayUsingPredicate:diskPredicate]];
}