[gnome-games/wip/aplazas/playstation-disc-image: 16/16] Parse PlayStation disc images properly
- From: Adrien Plazas <aplazas src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games/wip/aplazas/playstation-disc-image: 16/16] Parse PlayStation disc images properly
- Date: Sat, 15 Jul 2017 08:18:55 +0000 (UTC)
commit d67b01a6b78c886acdae2baee68bbe78834ba024
Author: Adrien Plazas <kekun plazas laposte net>
Date: Fri Dec 23 06:10:22 2016 +0100
Parse PlayStation disc images properly
plugins/playstation/src/Makefile.am | 1 +
plugins/playstation/src/playstation-disc-image.c | 650 ++++++++++++++++++++++
plugins/playstation/src/playstation-header.vala | 104 +---
3 files changed, 677 insertions(+), 78 deletions(-)
---
diff --git a/plugins/playstation/src/Makefile.am b/plugins/playstation/src/Makefile.am
index 1b0067e..ca69157 100644
--- a/plugins/playstation/src/Makefile.am
+++ b/plugins/playstation/src/Makefile.am
@@ -36,6 +36,7 @@ libgames_playstation_plugin_la_DEPENDENCIES = \
libgames_playstation_plugin_la_SOURCES = \
$(BUILT_SOURCES) \
+ playstation-disc-image.c \
playstation-error.vala \
playstation-game-factory.vala \
playstation-header.vala \
diff --git a/plugins/playstation/src/playstation-disc-image.c
b/plugins/playstation/src/playstation-disc-image.c
new file mode 100644
index 0000000..f974bf5
--- /dev/null
+++ b/plugins/playstation/src/playstation-disc-image.c
@@ -0,0 +1,650 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+#include <errno.h>
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#include <gio/gio.h>
+
+////////////////////////////////////////////////////////////////////////
+// GamesDiscImageTime
+////////////////////////////////////////////////////////////////////////
+
+#define GAMES_DISC_IMAGE_FRAMES_PER_SECOND 75
+
+typedef struct {
+ guint8 minute;
+ guint8 second;
+ guint8 frame;
+} GamesDiscImageTime;
+
+static void
+games_disc_image_time_set_minute_second_frame (GamesDiscImageTime *time,
+ guint8 minute,
+ guint8 second,
+ guint8 frame)
+{
+ time->minute = minute;
+ time->second = second;
+ time->frame = frame;
+}
+
+static void
+games_disc_image_time_get_minute_second_frame (const GamesDiscImageTime *time,
+ guint8 *minute,
+ guint8 *second,
+ guint8 *frame)
+{
+ *minute = time->minute;
+ *second = time->second;
+ *frame = time->frame;
+}
+
+static void
+games_disc_image_time_set_from_time_reference (GamesDiscImageTime *time,
+ guint8 *time_reference)
+{
+ gint32 block; // The value of the clock containing the target time
+ int minute, second, frame;
+
+ block = GINT32_FROM_LE (*((gint32 *) time_reference));
+
+ block += 2 * GAMES_DISC_IMAGE_FRAMES_PER_SECOND;
+ minute = block / (60 * GAMES_DISC_IMAGE_FRAMES_PER_SECOND);
+ block = block - minute * (60 * GAMES_DISC_IMAGE_FRAMES_PER_SECOND);
+ second = block / GAMES_DISC_IMAGE_FRAMES_PER_SECOND;
+ frame = block - second * GAMES_DISC_IMAGE_FRAMES_PER_SECOND;
+
+ games_disc_image_time_set_minute_second_frame (time, minute, second, frame);
+}
+
+static gint
+games_disc_image_time_get_sector (const GamesDiscImageTime *time)
+{
+ guint8 minute, second, frame;
+ games_disc_image_time_get_minute_second_frame (time, &minute, &second, &frame);
+
+ return (minute * 60 + second - 2) * GAMES_DISC_IMAGE_FRAMES_PER_SECOND + frame;
+}
+
+static void
+games_disc_image_time_increment (GamesDiscImageTime *time)
+{
+ guint8 minute, second, frame;
+ games_disc_image_time_get_minute_second_frame (time, &minute, &second, &frame);
+
+ frame++;
+ if (frame == GAMES_DISC_IMAGE_FRAMES_PER_SECOND) {
+ frame = 0;
+ second++;
+ if (second == 60) {
+ second = 0;
+ minute++;
+ }
+ }
+
+ games_disc_image_time_set_minute_second_frame (time, minute, second, frame);
+}
+
+////////////////////////////////////////////////////////////////////////
+// GamesDiscFrame
+////////////////////////////////////////////////////////////////////////
+
+#define GAMES_DISC_IMAGE_FRAME_SIZE 2352
+#define GAMES_DISC_IMAGE_FRAME_HEADER_SIZE 12
+
+typedef struct _GamesDiscFrameMode1 GamesDiscFrameMode1;
+struct _GamesDiscFrameMode1 {
+ guint8 synchronization[12];
+ guint8 header[12];
+ guint8 content[2048];
+ guint8 error_correction_code[280];
+};
+
+typedef struct _GamesDiscFrameMode2 GamesDiscFrameMode2;
+struct _GamesDiscFrameMode2 {
+ guint8 synchronization[12];
+ guint8 content[2340];
+};
+
+typedef union _GamesDiscFrame GamesDiscFrame;
+union _GamesDiscFrame {
+ GamesDiscFrameMode1 mode1;
+ GamesDiscFrameMode2 mode2;
+};
+
+////////////////////////////////////////////////////////////////////////
+// GamesDiscFileInfo
+////////////////////////////////////////////////////////////////////////
+
+typedef struct _GamesDiscFileInfo GamesDiscFileInfo;
+struct _GamesDiscFileInfo {
+ guint8 length;
+ guint8 ext_attr_length;
+ guint8 extent[8];
+ guint8 size[8];
+ guint8 date[7];
+ guint8 flags;
+ guint8 file_unit_size;
+ guint8 interleave;
+ guint8 volume_sequence_number[4];
+ guint8 name_length;
+};
+
+typedef gboolean (*GamesDiscFileInfoForeachCallback) (GamesDiscFileInfo *file_info, gpointer user_data);
+
+static gboolean
+games_disc_file_info_is_directory (GamesDiscFileInfo *file_info)
+{
+ g_return_val_if_fail (file_info != NULL, FALSE);
+
+ return file_info->flags & 0x2;
+}
+
+static gboolean
+games_disc_file_info_is_valid (const GamesDiscFileInfo *file_info)
+{
+ // FIXME Magic number, I have no idea what it is but it works.
+ const gsize MAGIC_SIZE = 47;
+
+ g_return_val_if_fail (file_info != NULL, FALSE);
+
+ return file_info->length >= MAGIC_SIZE + file_info->name_length;
+}
+
+static gchar *
+games_disc_file_info_access_name (GamesDiscFileInfo *file_info)
+{
+ g_return_val_if_fail (file_info != NULL, NULL);
+
+ return (gchar *) file_info + sizeof (GamesDiscFileInfo);
+}
+
+static gchar *
+games_disc_file_info_get_name (GamesDiscFileInfo *file_info)
+{
+ g_return_val_if_fail (file_info != NULL, NULL);
+
+ return g_strndup (games_disc_file_info_access_name (file_info), file_info->name_length);
+}
+
+static GamesDiscFileInfo *
+games_disc_file_info_get_next (const GamesDiscFileInfo *file_info)
+{
+ g_return_val_if_fail (file_info != NULL, NULL);
+
+ if (!games_disc_file_info_is_valid (file_info))
+ return NULL;
+
+ return (GamesDiscFileInfo *) ((gpointer) file_info + file_info->length);
+}
+
+static void
+games_disc_file_info_foreach_file (GamesDiscFileInfo *file_info,
+ gsize size,
+ GamesDiscFileInfoForeachCallback callback,
+ gpointer user_data)
+{
+ GamesDiscFileInfo *current;
+ GamesDiscFileInfo *next;
+
+ g_return_if_fail (file_info != NULL);
+
+ for (current = file_info; current != NULL && games_disc_file_info_is_valid (current); current =
games_disc_file_info_get_next (current)) {
+ // The file info should never go beyond the end of the buffer.
+ if ((gpointer) current - (gpointer) file_info + sizeof (GamesDiscFileInfo) >= size ||
+ (gpointer) current - (gpointer) file_info + current->length >= size)
+ break;
+
+ if (!callback (current, user_data))
+ break;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// GamesDisc
+////////////////////////////////////////////////////////////////////////
+
+struct _GamesDiscImage {
+ FILE *file_handle;
+ GFileInputStream *input_stream;
+};
+
+typedef struct _GamesDiscImage GamesDiscImage;
+
+static void
+games_disc_image_open (GamesDiscImage *disc,
+ const char *filename,
+ GError **error)
+{
+ GFile *file;
+ GError *tmp_error = NULL;
+
+ file = g_file_new_for_path (filename);
+ g_clear_object (&disc->input_stream);
+ disc->input_stream = g_file_read (file, NULL, &tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+ g_object_unref(file);
+
+ return;
+ }
+
+ g_object_unref(file);
+}
+
+static void
+games_disc_image_dispose (GamesDiscImage *disc)
+{
+ g_clear_object (&disc->input_stream);
+}
+
+gboolean
+games_disc_image_read_frame (GamesDiscImage *disc,
+ const GamesDiscImageTime *time,
+ GamesDiscFrame *frame,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gssize read;
+ gsize offset;
+ GError *tmp_error = NULL;
+
+ g_return_val_if_fail (disc != NULL, FALSE);
+ g_return_val_if_fail (time != NULL, FALSE);
+ g_return_val_if_fail (frame != NULL, FALSE);
+
+ // FIXME Check the multiplication doesn't overflow.
+ offset = games_disc_image_time_get_sector (time) * sizeof (GamesDiscFrame);
+ g_seekable_seek (G_SEEKABLE (disc->input_stream),
+ offset, G_SEEK_SET,
+ cancellable, &tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ read = g_input_stream_read (G_INPUT_STREAM (disc->input_stream),
+ frame, sizeof (GamesDiscFrame),
+ cancellable, &tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ return read == sizeof (GamesDiscFrame);
+}
+
+gboolean
+games_disc_image_read_directory (GamesDiscImage *disc,
+ GamesDiscImageTime *time,
+ guint8 *dst,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gssize read;
+ gint sector;
+ GError *tmp_error = NULL;
+
+ sector = games_disc_image_time_get_sector(time);
+ g_seekable_seek (G_SEEKABLE (disc->input_stream),
+ sector * GAMES_DISC_IMAGE_FRAME_SIZE + GAMES_DISC_IMAGE_FRAME_HEADER_SIZE + 12,
+ G_SEEK_SET, cancellable, &tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ read = g_input_stream_read (G_INPUT_STREAM (disc->input_stream),
+ dst, 2048,
+ cancellable, &tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ if (read == -1)
+ return FALSE;
+
+ games_disc_image_time_increment (time);
+
+ sector = games_disc_image_time_get_sector(time);
+ g_seekable_seek (G_SEEKABLE (disc->input_stream),
+ sector * GAMES_DISC_IMAGE_FRAME_SIZE + GAMES_DISC_IMAGE_FRAME_HEADER_SIZE + 12,
+ G_SEEK_SET, cancellable, &tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ read = g_input_stream_read (G_INPUT_STREAM (disc->input_stream),
+ dst + 2048, 2048,
+ cancellable, &tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ if (read == -1)
+ return FALSE;
+
+ return TRUE;
+}
+
+typedef struct {
+ const gchar *filename;
+ GamesDiscImageTime *time;
+ gboolean is_dir;
+ gboolean found;
+} GetFileData;
+
+static gboolean
+get_file_co (GamesDiscFileInfo *file_info,
+ gpointer user_data)
+{
+ GetFileData *data = (GetFileData *) user_data;
+
+ if (games_disc_file_info_is_directory (file_info)) {
+ if (g_ascii_strncasecmp (games_disc_file_info_access_name (file_info), data->filename,
file_info->name_length) == 0) {
+ if (data->filename[file_info->name_length] != '\\')
+ return TRUE;
+
+ data->filename += file_info->name_length + 1;
+
+ games_disc_image_time_set_from_time_reference (data->time, file_info->extent);
+ data->is_dir = TRUE;
+ data->found = TRUE;
+
+ return FALSE;
+ }
+ }
+ else {
+ if (g_ascii_strncasecmp (games_disc_file_info_access_name (file_info), data->filename, strlen
(data->filename)) == 0) {
+ games_disc_image_time_set_from_time_reference (data->time, file_info->extent);
+ data->is_dir = FALSE;
+ data->found = TRUE;
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+games_disc_image_get_file (GamesDiscImage *disc,
+ GamesDiscFileInfo *file_info,
+ const gchar *filename,
+ GamesDiscImageTime *time,
+ GCancellable *cancellable,
+ GError **error)
+{
+ guint8 ddir[4096];
+ GetFileData data = { 0 };
+ gboolean success;
+ GError *tmp_error = NULL;
+
+ g_return_val_if_fail (filename != NULL, FALSE);
+
+ data.filename = filename;
+ data.time = time;
+ data.is_dir = TRUE;
+ data.found = FALSE;
+
+ while (data.is_dir) {
+ data.filename = filename;
+ data.time = time;
+ data.is_dir = FALSE;
+ data.found = FALSE;
+
+ games_disc_file_info_foreach_file (file_info, 4096, get_file_co, &data);
+
+ if (data.found && data.is_dir) {
+ success = games_disc_image_read_directory (disc, time, ddir, cancellable, &tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ if (!success)
+ return FALSE;
+
+ file_info = (GamesDiscFileInfo *) ddir;
+
+ break; // Parse the sub directory.
+ }
+ }
+
+ return data.found;
+}
+
+////////////////////////////////////////////////////////////////////////
+// PlayStation
+////////////////////////////////////////////////////////////////////////
+
+#define SYSTEM_CNF "SYSTEM.CNF;1"
+#define PSX_EXE "PSX.EXE;1"
+
+typedef struct _PlayStationGamesDiscInfo {
+ gchar *label;
+ gchar *exe;
+} PlayStationGamesDiscInfo;
+
+gboolean
+games_disc_image_get_playstation_info (GamesDiscImage *disc,
+ PlayStationGamesDiscInfo *games_disc_image_info,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gchar label_buffer[33] = "";
+
+ GamesDiscFileInfo *dir;
+ GamesDiscImageTime time;
+ guchar mdir[4096];
+ gchar exe_buffer[256];
+ gint i, len, c;
+ gchar *ptr;
+ GamesDiscFrame frame;
+ gboolean success;
+ GError *tmp_error = NULL;
+
+ games_disc_image_time_set_minute_second_frame (&time, 0, 2, 0x10);
+ success = games_disc_image_read_frame (disc, &time, &frame, cancellable, &tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ if (!success)
+ return FALSE;
+
+ memset (label_buffer, 0, sizeof (label_buffer));
+ memset (exe_buffer, 0, sizeof (exe_buffer));
+
+ strncpy (label_buffer, (const char *) frame.mode2.content + 52, 32);
+
+ // Skip head and sub, and go to the root directory record
+ dir = (GamesDiscFileInfo *) (frame.mode1.content + 156);
+
+ games_disc_image_time_set_from_time_reference (&time, dir->extent);
+
+ success = games_disc_image_read_directory (disc, &time, mdir, cancellable, &tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ if (!success)
+ return FALSE;
+
+ // Look for ststem configuration.
+
+ success = games_disc_image_get_file (disc, (GamesDiscFileInfo *) mdir, SYSTEM_CNF, &time, cancellable,
&tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ if (success) {
+ if (!games_disc_image_read_frame (disc, &time, &frame, cancellable, &tmp_error))
+ return FALSE;
+
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ // Look of "BOOT = cdrom:\\"
+
+ sscanf ((char *) frame.mode1.content, "BOOT = cdrom:\\%255s", exe_buffer);
+ success = games_disc_image_get_file (disc, (GamesDiscFileInfo *) mdir, exe_buffer, &time, cancellable,
&tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ if (success) {
+ if (games_disc_image_info != NULL) {
+ games_disc_image_info->label = strndup (label_buffer, sizeof (label_buffer));
+ games_disc_image_info->exe = strndup (exe_buffer, sizeof (exe_buffer));
+ }
+
+ return TRUE;
+ }
+
+ // Look of "BOOT = cdrom:"
+
+ sscanf ((char *) frame.mode1.content, "BOOT = cdrom:%255s", exe_buffer);
+ success = games_disc_image_get_file (disc, (GamesDiscFileInfo *) mdir, exe_buffer, &time, cancellable,
&tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ if (success) {
+ if (games_disc_image_info != NULL) {
+ games_disc_image_info->label = strndup (label_buffer, sizeof (label_buffer));
+ games_disc_image_info->exe = strndup (exe_buffer, sizeof (exe_buffer));
+ }
+
+ return TRUE;
+ }
+
+ // Look of "cdrom:"
+
+ ptr = strstr((gchar *) frame.mode1.content, "cdrom:"); // Possibly the executable is in some subdir.
+ if (ptr == NULL)
+ return FALSE;
+
+ // Skip "cdrom:".
+ ptr += 6;
+
+ // Skip slashes.
+ while (*ptr == '\\' || *ptr == '/')
+ ptr++;
+
+ strncpy (exe_buffer, ptr, 255);
+ exe_buffer[255] = '\0';
+ ptr = exe_buffer;
+
+ // Keep only the first line.
+ while (*ptr != '\0' && *ptr != '\r' && *ptr != '\n')
+ ptr++;
+ *ptr = '\0';
+
+ success = games_disc_image_get_file (disc, (GamesDiscFileInfo *) mdir, exe_buffer, &time, cancellable,
&tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ if (success) {
+ if (games_disc_image_info != NULL) {
+ games_disc_image_info->label = strndup (label_buffer, sizeof (label_buffer));
+ games_disc_image_info->exe = strndup (exe_buffer, sizeof (exe_buffer));
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ // Look for the default executable.
+
+ success = games_disc_image_get_file (disc, (GamesDiscFileInfo *) mdir, PSX_EXE, &time, cancellable,
&tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+
+ return FALSE;
+ }
+
+ if (success) {
+ if (games_disc_image_info != NULL) {
+ games_disc_image_info->label = strndup (label_buffer, sizeof (label_buffer));
+ games_disc_image_info->exe = strndup (PSX_EXE, sizeof (PSX_EXE));
+ }
+
+ return TRUE;
+ }
+
+ // SYSTEM.CNF and PSX.EXE not found.
+
+ return FALSE;
+}
+
+gboolean
+get_playstation_info (const gchar *image_filename,
+ gchar **label,
+ gchar **exe,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GamesDiscImage disc = { 0 };
+ gboolean success;
+ GError *tmp_error = NULL;
+
+ games_disc_image_open (&disc, image_filename, &tmp_error);
+ if (tmp_error != NULL) {
+ g_debug ("%s", tmp_error->message);
+ g_error_free (tmp_error);
+ games_disc_image_dispose (&disc);
+
+ return FALSE;
+ }
+
+ PlayStationGamesDiscInfo games_disc_image_info = { 0 };
+ success = games_disc_image_get_playstation_info (&disc, &games_disc_image_info, cancellable, &tmp_error);
+ if (tmp_error != NULL) {
+ g_debug ("%s", tmp_error->message);
+ g_error_free (tmp_error);
+ games_disc_image_dispose (&disc);
+
+ return FALSE;
+ }
+
+ games_disc_image_dispose (&disc);
+
+ if (success) {
+ *label = games_disc_image_info.label;
+ *exe = games_disc_image_info.exe;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/plugins/playstation/src/playstation-header.vala b/plugins/playstation/src/playstation-header.vala
index 19d1275..b63c447 100644
--- a/plugins/playstation/src/playstation-header.vala
+++ b/plugins/playstation/src/playstation-header.vala
@@ -1,24 +1,7 @@
// This file is part of GNOME Games. License: GPL-3.0+.
private class Games.PlayStationHeader : Object {
- private const size_t[] HEADER_OFFSETS = {
- 0x85D2, // .bin.ecm
- 0x9320, // .bin
- 0x9360, // .iso
- };
- private const size_t HEADER_TITLE_OFFSET = 0x20;
- private const string HEADER_MAGIC_VALUE = "PLAYSTATION";
-
- private const size_t[] BOOT_OFFSETS = {
- 0xBE64, // .bin.ecm
- 0xD368, // .bin
- 0xD3A8, // .iso
- 0xA9F98, // .bin
- };
- private const string BOOT_MAGIC_VALUE = "BOOT";
-
// The ID prefixes must always be in uppercase.
- private const string[] IDS = { "SLUS", "SCUS", "SLES", "SCES", "SLPS", "SLPM", "SCPS" };
private const size_t DISC_ID_SIZE = 10;
private static Regex disc_id_regex;
@@ -38,83 +21,45 @@ private class Games.PlayStationHeader : Object {
if (_disc_id != null)
return;
- _disc_id = get_id_from_boot ();
+ string label;
+ string exe;
+ if (!get_playstation_info (file.get_path (), out label, out exe))
+ throw new PlayStationError.INVALID_HEADER (_("Not a PlayStation disc: ā%sā."),
file.get_uri ());
+
+ _disc_id = parse_id_from_exe (exe);
if (_disc_id != null)
return;
- _disc_id = search_id_in_header ();
+ _disc_id = parse_id_from_label (label);
if (_disc_id != null)
return;
throw new PlayStationError.INVALID_HEADER (_("Invalid PlayStation header: disc ID not found
in ā%sā."), file.get_uri ());
}
- private string? search_id_in_header () throws Error {
- var offset = get_header_offset ();
- if (offset == null)
- return null;
-
- var stream = new StringInputStream (file);
- var header = stream.read_string_for_size (offset + HEADER_TITLE_OFFSET, DISC_ID_SIZE);
-
- var raw_id = header.up ();
- raw_id = raw_id.replace ("_", "-");
-
- foreach (var id in IDS) {
- if (!(id in header))
- continue;
-
- if (is_a_disc_id (raw_id))
- return raw_id;
- }
-
- return null;
- }
-
- private size_t? get_header_offset () throws Error {
- var stream = new StringInputStream (file);
+ private string? parse_id_from_exe (string exe) throws Error {
+ var disc_id = exe.strip ();
+ disc_id = disc_id.split (";")[0];
+ disc_id = disc_id.replace ("_", "-");
+ disc_id = disc_id.replace (".", "");
+ disc_id = disc_id.up ();
- foreach (var offset in HEADER_OFFSETS)
- if (stream.has_string (offset, HEADER_MAGIC_VALUE))
- return offset;
-
- return null;
- }
-
- private string? get_id_from_boot () throws Error {
- var offset = get_boot_offset ();
- if (offset == null)
+ if (!is_a_disc_id (disc_id))
return null;
- var stream = new StringInputStream (file);
- var header = stream.read_string (offset);
- header = header.up ();
-
- foreach (var id in IDS) {
- if (!(id in header))
- continue;
-
- var raw_id = header.split (id)[1];
- raw_id = raw_id.split (";")[0];
- raw_id = raw_id.replace ("_", "-");
- raw_id = raw_id.replace (".", "");
- raw_id = (id + raw_id).up ();
-
- if (is_a_disc_id (raw_id))
- return raw_id;
- }
-
- return null;
+ return disc_id;
}
- private size_t? get_boot_offset () throws Error {
- var stream = new StringInputStream (file);
+ private string? parse_id_from_label (string label) throws Error {
+ var disc_id = label.strip ();
+ disc_id = disc_id.replace ("_", "-");
+ disc_id = disc_id.strip ();
+ disc_id = disc_id.up ();
- foreach (var offset in BOOT_OFFSETS)
- if (stream.has_string (offset, BOOT_MAGIC_VALUE))
- return offset;
+ if (!is_a_disc_id (disc_id))
+ return null;
- return null;
+ return disc_id;
}
private static bool is_a_disc_id (string disc_id) {
@@ -123,4 +68,7 @@ private class Games.PlayStationHeader : Object {
return disc_id_regex.match (disc_id);
}
+
+ [CCode (cname = "get_playstation_info")]
+ private static extern bool get_playstation_info (string filename, out string label, out string exe)
throws Error;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]