[gnome-games] dreamcast: Add the Gdi class to parse .gdi files
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games] dreamcast: Add the Gdi class to parse .gdi files
- Date: Sat, 7 Nov 2020 16:19:20 +0000 (UTC)
commit 0cf57fb5fc2540fd912fd3f6743bc256931f7fc7
Author: Adrien Plazas <kekun plazas laposte net>
Date: Tue Nov 3 09:25:42 2020 +0100
dreamcast: Add the Gdi class to parse .gdi files
This is needed to properly support Dreamcast games in the .gdi format.
plugins/dreamcast/src/gdi/gdi-error.vala | 10 ++
plugins/dreamcast/src/gdi/gdi-track-node.vala | 10 ++
plugins/dreamcast/src/gdi/gdi.vala | 152 ++++++++++++++++++++++++++
plugins/dreamcast/src/meson.build | 4 +
4 files changed, 176 insertions(+)
---
diff --git a/plugins/dreamcast/src/gdi/gdi-error.vala b/plugins/dreamcast/src/gdi/gdi-error.vala
new file mode 100644
index 00000000..5f29569a
--- /dev/null
+++ b/plugins/dreamcast/src/gdi/gdi-error.vala
@@ -0,0 +1,10 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+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/gdi/gdi-track-node.vala b/plugins/dreamcast/src/gdi/gdi-track-node.vala
new file mode 100644
index 00000000..6a376024
--- /dev/null
+++ b/plugins/dreamcast/src/gdi/gdi-track-node.vala
@@ -0,0 +1,10 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+public class Games.GdiTrackNode : Object {
+ public File file { construct; get; }
+ public int track_number { construct; get; }
+
+ public GdiTrackNode (File file, int track_number) {
+ Object (file: file, track_number: track_number);
+ }
+}
diff --git a/plugins/dreamcast/src/gdi/gdi.vala b/plugins/dreamcast/src/gdi/gdi.vala
new file mode 100644
index 00000000..04d3e004
--- /dev/null
+++ b/plugins/dreamcast/src/gdi/gdi.vala
@@ -0,0 +1,152 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+public class Games.Gdi : Object {
+ private const string NEW_LINE = "\n";
+
+ private File _file;
+ public File file {
+ get { return _file; }
+ }
+
+ public uint tracks_number {
+ get { return tracks.length; }
+ }
+
+ private GdiTrackNode[] tracks;
+
+ public Gdi (File file) throws Error {
+ _file = file;
+
+ parse ();
+ }
+
+ public GdiTrackNode get_track (uint i) throws Error {
+ if (i >= tracks.length)
+ throw new GdiError.NOT_A_TRACK ("“%s” doesn’t have a track for index %u.",
file.get_uri (), i);
+
+ return tracks[i];
+ }
+
+ private string[] tokenize () throws Error {
+ var stream = Unicode.read (file, Unicode.Encoding.UTF_8);
+ var data_stream = new DataInputStream (stream);
+
+ string[] tokens = {};
+
+ string? line;
+ while ((line = data_stream.read_line_utf8 ()) != null)
+ foreach (var token in tokenize_line (line))
+ tokens += token;
+
+ return tokens;
+ }
+
+ private static Regex token_regex;
+ private static string[] tokenize_line (string line) {
+ if (token_regex == null)
+ // Matches words or "double quoted strings" (no escaping).
+ token_regex = /\s*([^"\s]+)|(".+?")\s*/;
+
+ string[] tokens = {};
+ foreach (var token in token_regex.split (line))
+ switch (token) {
+ case "\r":
+ case "\r\n":
+ tokens += NEW_LINE;
+
+ break;
+ case "":
+ case " ":
+ break;
+ default:
+ tokens += token;
+
+ break;
+ }
+
+ // Makes sure the token set ends by a new line.
+ if (tokens.length != 0 && tokens[tokens.length - 1] != NEW_LINE)
+ tokens += NEW_LINE;
+
+ return tokens;
+ }
+
+ private void parse () throws Error {
+ var tokens = tokenize ();
+
+ size_t line = 1;
+ 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);
+ else
+ tracks += parse_track_line (ref tokens, ref i, line);
+ }
+
+ private void parse_track_count_line (ref string[] tokens, ref size_t i, size_t line) throws GdiError {
+ // Skip the track number token.
+ skip_token (ref tokens, ref i, line);
+ is_end_of_line (ref tokens, ref i, line);
+ }
+
+ private GdiTrackNode parse_track_line (ref string[] tokens, ref size_t i, size_t line) throws
GdiError {
+ var track_number_string = get_token (ref tokens, ref i, line);
+
+ // Skip the track offset token.
+ skip_token (ref tokens, ref i, line);
+
+ // Skip the track mode tokens.
+ skip_token (ref tokens, ref i, line);
+ skip_token (ref tokens, ref i, line);
+
+ var file_name = get_token (ref tokens, ref i, line);
+ if (file_name.has_prefix ("\"") && file_name.has_suffix ("\"") && file_name.length > 1)
+ file_name = file_name[1: file_name.length - 1];
+ var dir = file.get_parent ();
+ var child_file = dir.get_child (file_name);
+
+ // Skip the unknown token.
+ skip_token (ref tokens, ref i, line);
+ is_end_of_line (ref tokens, ref i, line);
+
+ var track_number = int.parse (track_number_string);
+ 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);
+ }
+
+ private void skip_token (ref string[] tokens, ref size_t i, size_t line) throws GdiError {
+ if (i >= tokens.length)
+ throw new GdiError.UNEXPECTED_EOF ("%s:%lu: Unexpected end of file, expected a
token.", file.get_basename (), line);
+
+ 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++;
+ }
+
+ private string get_token (ref string[] tokens, ref size_t i, size_t line) throws GdiError {
+ if (i >= tokens.length)
+ throw new GdiError.UNEXPECTED_EOF ("%s:%lu: Unexpected end of file, expected a
token.", file.get_basename (), line);
+
+ 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;
+ }
+
+ private void is_end_of_line (ref string[] tokens, ref size_t i, size_t line) throws GdiError {
+ if (i < tokens.length && tokens[i] != NEW_LINE)
+ throw new GdiError.UNEXPECTED_TOKEN ("%s:%lu: Unexpected token %s, expected end of
line.", file.get_basename (), line, tokens[i]);
+
+ i++;
+ }
+}
diff --git a/plugins/dreamcast/src/meson.build b/plugins/dreamcast/src/meson.build
index a938bb73..f4b47ac1 100644
--- a/plugins/dreamcast/src/meson.build
+++ b/plugins/dreamcast/src/meson.build
@@ -2,6 +2,10 @@ vala_sources = [
'dreamcast-error.vala',
'dreamcast-header.vala',
'dreamcast-plugin.vala',
+
+ 'gdi/gdi.vala',
+ 'gdi/gdi-error.vala',
+ 'gdi/gdi-track-node.vala',
]
c_args = [
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]