From 63c4a164595349569b067700cd922f326ecd41c5 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Wed, 30 Jan 2019 18:28:49 +0100 Subject: [PATCH] preliminary support for CUE files --- core/cfg/cl.cpp | 3 +- core/imgread/common.cpp | 2 + core/imgread/cue.cpp | 177 ++++++++++++++++++ .../reicast/src/dreamcast/AndroidManifest.xml | 10 + .../emulator/PathsViewController.m | 4 +- 5 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 core/imgread/cue.cpp 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]]; }