[gnome-games] playstation: Add DiscImage



commit 3a28c93d5ab53f7083108d78902bda40677d8bc3
Author: Adrien Plazas <kekun plazas laposte net>
Date:   Sat Jul 15 11:34:34 2017 +0200

    playstation: Add DiscImage
    
    This will be used in the next commit to parse PlayStation disc images.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=775255

 plugins/playstation/src/Makefile.am  |    1 +
 plugins/playstation/src/disc-image.c |  227 ++++++++++++++++++++++++++++++++++
 plugins/playstation/src/disc-image.h |   66 ++++++++++
 3 files changed, 294 insertions(+), 0 deletions(-)
---
diff --git a/plugins/playstation/src/Makefile.am b/plugins/playstation/src/Makefile.am
index 418d093..6d82754 100644
--- a/plugins/playstation/src/Makefile.am
+++ b/plugins/playstation/src/Makefile.am
@@ -37,6 +37,7 @@ libgames_playstation_plugin_la_DEPENDENCIES = \
 libgames_playstation_plugin_la_SOURCES = \
        $(BUILT_SOURCES) \
        disc-file-info.c \
+       disc-image.c \
        disc-image-time.c \
        playstation-error.vala \
        playstation-game-factory.vala \
diff --git a/plugins/playstation/src/disc-image.c b/plugins/playstation/src/disc-image.c
new file mode 100644
index 0000000..bb25b2d
--- /dev/null
+++ b/plugins/playstation/src/disc-image.c
@@ -0,0 +1,227 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+#include "disc-image.h"
+
+#include <string.h>
+#include "disc-file-info.h"
+#include "disc-image-time.h"
+
+/* Private */
+
+#define GAMES_DISC_IMAGE_FRAME_SIZE           2352
+#define GAMES_DISC_IMAGE_FRAME_HEADER_SIZE    12
+
+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;
+}
+
+/* Public */
+
+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);
+}
+
+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;
+}
+
+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;
+}
diff --git a/plugins/playstation/src/disc-image.h b/plugins/playstation/src/disc-image.h
new file mode 100644
index 0000000..40699a4
--- /dev/null
+++ b/plugins/playstation/src/disc-image.h
@@ -0,0 +1,66 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+#ifndef DISC_IMAGE_H
+#define DISC_IMAGE_H
+
+#include <gio/gio.h>
+#include <glib.h>
+
+#include "disc-file-info.h"
+#include "disc-image-time.h"
+
+G_BEGIN_DECLS
+
+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;
+};
+
+typedef struct _GamesDiscImage GamesDiscImage;
+
+struct _GamesDiscImage {
+  GFileInputStream *input_stream;
+};
+
+void games_disc_image_open (GamesDiscImage  *disc,
+                            const char      *filename,
+                            GError         **error);
+void games_disc_image_dispose (GamesDiscImage *disc);
+gboolean games_disc_image_read_frame (GamesDiscImage            *disc,
+                                      const GamesDiscImageTime  *time,
+                                      GamesDiscFrame            *frame,
+                                      GCancellable              *cancellable,
+                                      GError                   **error);
+gboolean games_disc_image_read_directory (GamesDiscImage      *disc,
+                                          GamesDiscImageTime  *time,
+                                          guint8              *dst,
+                                          GCancellable        *cancellable,
+                                          GError             **error);
+gboolean games_disc_image_get_file (GamesDiscImage      *disc,
+                                    GamesDiscFileInfo   *file_info,
+                                    const gchar         *filename,
+                                    GamesDiscImageTime  *time,
+                                    GCancellable        *cancellable,
+                                    GError             **error);
+
+G_END_DECLS
+
+#endif /* DISC_IMAGE_H */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]