[gnome-games] dreamcast: Support .gdi files
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games] dreamcast: Support .gdi files
- Date: Sat, 7 Nov 2020 16:19:20 +0000 (UTC)
commit b82945159a271ba4c413b10f7d24764954afc592
Author: Adrien Plazas <kekun plazas laposte net>
Date: Tue Nov 3 09:27:38 2020 +0100
dreamcast: Support .gdi files
Fixes https://gitlab.gnome.org/GNOME/gnome-games/-/issues/48
data/org.gnome.Games.desktop.in.in | 2 +-
plugins/dreamcast/src/dreamcast-error.vala | 2 +
plugins/dreamcast/src/dreamcast-header.vala | 17 ++++++---
plugins/dreamcast/src/dreamcast-plugin.vala | 44 ++++++++++++++++++++--
plugins/dreamcast/src/{gdi => }/gdi.vala | 53 +++++++++++++++++----------
plugins/dreamcast/src/gdi/gdi-error.vala | 10 -----
plugins/dreamcast/src/gdi/gdi-track-node.vala | 10 -----
plugins/dreamcast/src/meson.build | 5 +--
8 files changed, 89 insertions(+), 54 deletions(-)
---
diff --git a/data/org.gnome.Games.desktop.in.in b/data/org.gnome.Games.desktop.in.in
index 14d62d37..779e780a 100644
--- a/data/org.gnome.Games.desktop.in.in
+++ b/data/org.gnome.Games.desktop.in.in
@@ -13,4 +13,4 @@ Type=Application
StartupNotify=true
DBusActivatable=true
Categories=GNOME;GTK;Player;Game;
-MimeType=application/vnd.nintendo.snes.rom;application/x-amiga-disk-format;application/x-atari-2600-rom;application/x-atari-7800-rom;application/x-atari-lynx-rom;application/x-cue;application/x-discjuggler-cd-image;application/x-doom-wad;application/x-fds-disk;application/x-gameboy-color-rom;application/x-gameboy-rom;application/x-gamecube-rom;application/x-gamegear-rom;application/x-gba-rom;application/x-genesis-32x-rom;application/x-genesis-rom;application/x-love-game;application/x-mame-rom;application/x-ms-dos-executable;application/x-n64-rom;application/x-neo-geo-pocket-color-rom;application/x-neo-geo-pocket-rom;application/x-nes-rom;application/x-nintendo-ds-rom;application/x-pc-engine-rom;application/x-playstation-rom;application/x-saturn-rom;application/x-sega-cd-rom;application/x-sega-pico-rom;application/x-sg1000-rom;application/x-sms-rom;application/x-virtual-boy-rom;application/x-wii-rom;application/x-wii-wad;application/x-wonderswan-color-rom;application/x-wonderswan-rom
;application/zip;
+MimeType=application/vnd.nintendo.snes.rom;application/x-amiga-disk-format;application/x-atari-2600-rom;application/x-atari-7800-rom;application/x-atari-lynx-rom;application/x-cue;application/x-discjuggler-cd-image;application/x-doom-wad;application/x-fds-disk;application/x-gameboy-color-rom;application/x-gameboy-rom;application/x-gamecube-rom;application/x-gamegear-rom;application/x-gba-rom;application/x-gd-rom-cue;application/x-genesis-32x-rom;application/x-genesis-rom;application/x-love-game;application/x-mame-rom;application/x-ms-dos-executable;application/x-n64-rom;application/x-neo-geo-pocket-color-rom;application/x-neo-geo-pocket-rom;application/x-nes-rom;application/x-nintendo-ds-rom;application/x-pc-engine-rom;application/x-playstation-rom;application/x-saturn-rom;application/x-sega-cd-rom;application/x-sega-pico-rom;application/x-sg1000-rom;application/x-sms-rom;application/x-virtual-boy-rom;application/x-wii-rom;application/x-wii-wad;application/x-wonderswan-color-rom;app
lication/x-wonderswan-rom;application/zip;
diff --git a/plugins/dreamcast/src/dreamcast-error.vala b/plugins/dreamcast/src/dreamcast-error.vala
index 2a521659..1bb2dd8c 100644
--- a/plugins/dreamcast/src/dreamcast-error.vala
+++ b/plugins/dreamcast/src/dreamcast-error.vala
@@ -1,5 +1,7 @@
// This file is part of GNOME Games. License: GPL-3.0+.
errordomain Games.DreamcastError {
+ INVALID_GDI,
+ INVALID_FILE_TYPE,
INVALID_HEADER,
}
diff --git a/plugins/dreamcast/src/dreamcast-header.vala b/plugins/dreamcast/src/dreamcast-header.vala
index 9f2a5516..c9004529 100644
--- a/plugins/dreamcast/src/dreamcast-header.vala
+++ b/plugins/dreamcast/src/dreamcast-header.vala
@@ -1,6 +1,7 @@
// This file is part of GNOME Games. License: GPL-3.0+.
private class Games.DreamcastHeader : Object {
+ private const size_t HEADER_OFFSET = 0x10;
private const size_t HEADER_SIZE = 0x100;
private const size_t MAGIC_OFFSET = 0x0;
@@ -43,17 +44,23 @@ private class Games.DreamcastHeader : Object {
if (header_offset != null)
return header_offset;
+ if (lookup_header_offset (HEADER_OFFSET)) {
+ header_offset = HEADER_OFFSET;
+
+ return header_offset;
+ }
+
var path = file.get_path ();
var header_offsets = Grep.get_offsets (path, MAGIC_VALUE);
foreach (var offset in header_offsets)
- if (lookup_header_offset (offset))
+ if (lookup_header_offset (offset)) {
header_offset = offset;
- if (header_offset == null)
- throw new DreamcastError.INVALID_HEADER ("The file doesn’t have a Dreamcast header.");
+ return header_offset;
+ }
- return header_offset;
+ throw new DreamcastError.INVALID_HEADER ("The file doesn’t have a Dreamcast header.");
}
private bool lookup_header_offset (size_t offset) throws Error {
@@ -61,7 +68,7 @@ private class Games.DreamcastHeader : Object {
if (!stream.has_string (offset + MAGIC_OFFSET, MAGIC_VALUE))
return false;
- var header = stream.read_string_for_size (offset + MAGIC_OFFSET, HEADER_SIZE);
+ var header = stream.read_string_for_size (offset, HEADER_SIZE);
return header.length == HEADER_SIZE && header.is_ascii ();
}
diff --git a/plugins/dreamcast/src/dreamcast-plugin.vala b/plugins/dreamcast/src/dreamcast-plugin.vala
index 7f620922..c3aacae1 100644
--- a/plugins/dreamcast/src/dreamcast-plugin.vala
+++ b/plugins/dreamcast/src/dreamcast-plugin.vala
@@ -1,16 +1,18 @@
// This file is part of GNOME Games. License: GPL-3.0+.
private class Games.DreamcastPlugin : Object, Plugin {
+ private const string GDI_MIME_TYPE = "application/x-gd-rom-cue";
private const string CDI_MIME_TYPE = "application/x-discjuggler-cd-image";
private const string DREAMCAST_MIME_TYPE = "application/x-dreamcast-rom";
private const string PLATFORM_ID = "Dreamcast";
private const string PLATFORM_NAME = _("Dreamcast");
private const string PLATFORM_UID_PREFIX = "dreamcast";
+ private const string[] MIME_TYPES = { GDI_MIME_TYPE, CDI_MIME_TYPE };
private static RetroPlatform platform;
static construct {
- platform = new RetroPlatform (PLATFORM_ID, PLATFORM_NAME, { CDI_MIME_TYPE },
PLATFORM_UID_PREFIX);
+ platform = new RetroPlatform (PLATFORM_ID, PLATFORM_NAME, MIME_TYPES, PLATFORM_UID_PREFIX);
}
public Platform[] get_platforms () {
@@ -18,13 +20,14 @@ private class Games.DreamcastPlugin : Object, Plugin {
}
public string[] get_mime_types () {
- return { CDI_MIME_TYPE };
+ return MIME_TYPES;
}
public UriGameFactory[] get_uri_game_factories () {
var game_uri_adapter = new GenericGameUriAdapter (game_for_uri);
var factory = new GenericUriGameFactory (game_uri_adapter);
- factory.add_mime_type (CDI_MIME_TYPE);
+ foreach (var mime_type in MIME_TYPES)
+ factory.add_mime_type (mime_type);
return { factory };
}
@@ -44,7 +47,26 @@ private class Games.DreamcastPlugin : Object, Plugin {
private static Game game_for_uri (Uri uri) throws Error {
var file = uri.to_file ();
- var header = new DreamcastHeader (file);
+ var file_info = file.query_info (FileAttribute.STANDARD_CONTENT_TYPE,
FileQueryInfoFlags.NONE);
+ var mime_type = file_info.get_content_type ();
+
+ File bin_file;
+ switch (mime_type) {
+ case GDI_MIME_TYPE:
+ var gdi = new Gdi (file);
+ gdi.parse ();
+ bin_file = get_binary_file (gdi);
+
+ break;
+ case CDI_MIME_TYPE:
+ bin_file = file;
+
+ break;
+ default:
+ throw new DreamcastError.INVALID_FILE_TYPE ("Invalid file type: expected %s or %s but
got %s for file %s.", GDI_MIME_TYPE, CDI_MIME_TYPE, mime_type, uri.to_string ());
+ }
+
+ var header = new DreamcastHeader (bin_file);
header.check_validity ();
var uid = new Uid (get_uid (header));
@@ -59,6 +81,20 @@ private class Games.DreamcastPlugin : Object, Plugin {
return game;
}
+
+ private static File get_binary_file (Gdi gdi) throws Error {
+ if (gdi.tracks_number == 0)
+ throw new DreamcastError.INVALID_GDI ("The file “%s” doesn’t have a track.",
gdi.file.get_uri ());
+
+ var track = gdi.get_track (0);
+ var file = track.file;
+
+ var file_info = file.query_info ("*", FileQueryInfoFlags.NONE);
+ if (file_info.get_content_type () != DREAMCAST_MIME_TYPE)
+ throw new DreamcastError.INVALID_FILE_TYPE ("The file “%s” doesn’t have a valid
Dreamcast binary file.", gdi.file.get_uri ());
+
+ return file;
+ }
}
[ModuleInit]
diff --git a/plugins/dreamcast/src/gdi/gdi.vala b/plugins/dreamcast/src/gdi.vala
similarity index 85%
rename from plugins/dreamcast/src/gdi/gdi.vala
rename to plugins/dreamcast/src/gdi.vala
index 04d3e004..80de9081 100644
--- a/plugins/dreamcast/src/gdi/gdi.vala
+++ b/plugins/dreamcast/src/gdi.vala
@@ -3,24 +3,26 @@
public class Games.Gdi : Object {
private const string NEW_LINE = "\n";
- private File _file;
- public File file {
- get { return _file; }
- }
+ public File file { get; construct; }
public uint tracks_number {
- get { return tracks.length; }
+ get {
+ assert (parsed);
+
+ return tracks.length;
+ }
}
+ private bool parsed = false;
private GdiTrackNode[] tracks;
- public Gdi (File file) throws Error {
- _file = file;
-
- parse ();
+ public Gdi (File file) {
+ Object (file: file);
}
public GdiTrackNode get_track (uint i) throws Error {
+ assert (parsed);
+
if (i >= tracks.length)
throw new GdiError.NOT_A_TRACK ("“%s” doesn’t have a track for index %u.",
file.get_uri (), i);
@@ -71,11 +73,15 @@ public class Games.Gdi : Object {
return tokens;
}
- private void parse () throws Error {
+ public void parse () throws Error {
+ assert (!parsed);
+
+ parsed = true;
+
var tokens = tokenize ();
size_t line = 1;
- for (size_t i = 0 ; i < tokens.length ; line++)
+ for (size_t i = 0; i < tokens.length; line++)
// Each case must consume the line completely.
if (line == 1)
parse_track_count_line (ref tokens, ref i, line);
@@ -113,7 +119,7 @@ public class Games.Gdi : Object {
if (track_number < 1 || track_number > 99)
throw new GdiError.INVALID_TRACK_NUMBER ("%s:%lu: Invalid track number %s, expected a
number in the 1-99 range.", file.get_basename (), line, track_number_string);
- return new GdiTrackNode (child_file, track_number);
+ return GdiTrackNode () { file = child_file, track_number = track_number };
}
private void skip_token (ref string[] tokens, ref size_t i, size_t line) throws GdiError {
@@ -123,8 +129,6 @@ public class Games.Gdi : Object {
if (tokens[i] == NEW_LINE)
throw new GdiError.UNEXPECTED_EOL ("%s:%lu: Unexpected end of line, expected a
token.", file.get_basename (), line);
- warning ("Skipping token `%s`", tokens[i]);
-
i++;
}
@@ -135,12 +139,7 @@ public class Games.Gdi : Object {
if (tokens[i] == NEW_LINE)
throw new GdiError.UNEXPECTED_EOL ("%s:%lu: Unexpected end of line, expected a
token.", file.get_basename (), line);
- warning ("Getting token `%s`", tokens[i]);
-
- var token = tokens[i];
- i++;
-
- return token;
+ return tokens[i++];
}
private void is_end_of_line (ref string[] tokens, ref size_t i, size_t line) throws GdiError {
@@ -150,3 +149,17 @@ public class Games.Gdi : Object {
i++;
}
}
+
+public struct Games.GdiTrackNode {
+ public File file;
+ public int track_number;
+}
+
+private errordomain Games.GdiError {
+ UNEXPECTED_TOKEN,
+ UNEXPECTED_EOL,
+ UNEXPECTED_EOF,
+ INVALID_TRACK_NUMBER,
+ INVALID_TRACK_MODE,
+ NOT_A_TRACK,
+}
diff --git a/plugins/dreamcast/src/meson.build b/plugins/dreamcast/src/meson.build
index f4b47ac1..90af8614 100644
--- a/plugins/dreamcast/src/meson.build
+++ b/plugins/dreamcast/src/meson.build
@@ -2,10 +2,7 @@ vala_sources = [
'dreamcast-error.vala',
'dreamcast-header.vala',
'dreamcast-plugin.vala',
-
- 'gdi/gdi.vala',
- 'gdi/gdi-error.vala',
- 'gdi/gdi-track-node.vala',
+ 'gdi.vala',
]
c_args = [
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]