[easytag] Port ogg_header.c to use GFile instead of POSIX IO
- From: David King <davidk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [easytag] Port ogg_header.c to use GFile instead of POSIX IO
- Date: Sun, 2 Jun 2013 17:22:01 +0000 (UTC)
commit 700c86aadc6e16e4941ceb06a37cfb0b9e57b4b0
Author: David King <amigadave amigadave com>
Date: Sun Jun 2 18:12:21 2013 +0100
Port ogg_header.c to use GFile instead of POSIX IO
Fixes bug 701467.
src/ogg_header.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++----
src/ogg_header.h | 3 +-
2 files changed, 166 insertions(+), 14 deletions(-)
---
diff --git a/src/ogg_header.c b/src/ogg_header.c
index fed435a..065e80b 100644
--- a/src/ogg_header.c
+++ b/src/ogg_header.c
@@ -24,7 +24,6 @@
#include <gtk/gtk.h>
#include <glib/gi18n-lib.h>
-#include <stdio.h>
#include <errno.h>
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
@@ -59,9 +58,146 @@ et_ogg_error_quark (void)
return g_quark_from_static_string ("et-ogg-error-quark");
}
-gboolean Ogg_Header_Read_File_Info (gchar *filename, ET_File_Info *ETFileInfo)
+/*
+ * EtOggState:
+ * @file: the Ogg file which is currently being parsed
+ * @istream: an input stream for the current Ogg file
+ * @error: either the most recent error, or %NULL
+ *
+ * The current state of the Ogg parser, for passing between the callbacks used
+ * in ov_open_callbacks().
+ */
+typedef struct
+{
+ GFile *file;
+ GInputStream *istream;
+ GError *error;
+} EtOggState;
+
+/*
+ * et_ogg_read_func:
+ * @ptr: the buffer to fill with data
+ * @size: the size of individual reads
+ * @nmemb: the number of members to read
+ * @datasource: the Ogg parser state
+ *
+ * Read a number of bytes from the Ogg file.
+ *
+ * Returns: the number of bytes read from the stream. Returns 0 on end-of-file.
+ * Sets errno and returns 0 on error
+ */
+static size_t
+et_ogg_read_func (void *ptr, size_t size, size_t nmemb, void *datasource)
+{
+ EtOggState *state = (EtOggState *)datasource;
+ gssize bytes_read;
+
+ bytes_read = g_input_stream_read (state->istream, ptr, size * nmemb, NULL,
+ &state->error);
+
+ if (bytes_read == -1)
+ {
+ /* FIXME: Convert state->error to errno. */
+ errno = EIO;
+ return 0;
+ }
+ else
+ {
+ return bytes_read;
+ }
+}
+
+/*
+ * et_ogg_seek_func:
+ * @datasource: the Ogg parser state
+ * @offset: the number of bytes to seek
+ * @whence: either %SEEK_SET, %SEEK_CUR or %SEEK_END
+ *
+ * Seek in the currently-open Ogg file.
+ *
+ * Returns: 0 on success, -1 and sets errno on error
+ */
+static int
+et_ogg_seek_func (void *datasource, ogg_int64_t offset, int whence)
+{
+ EtOggState *state = (EtOggState *)datasource;
+ GSeekType seektype;
+
+ if (!g_seekable_can_seek (G_SEEKABLE (state->istream)))
+ {
+ return -1;
+ }
+ else
+ {
+ switch (whence)
+ {
+ case SEEK_SET:
+ seektype = G_SEEK_SET;
+ break;
+ case SEEK_CUR:
+ seektype = G_SEEK_CUR;
+ break;
+ case SEEK_END:
+ seektype = G_SEEK_END;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (g_seekable_seek (G_SEEKABLE (state->istream), offset, seektype,
+ NULL, &state->error))
+ {
+ return 0;
+ }
+ else
+ {
+ errno = EBADF;
+ return -1;
+ }
+ }
+}
+
+/*
+ * et_ogg_close_func:
+ * @datasource: the Ogg parser state
+ *
+ * Close the Ogg stream and invalidate the parser state given by @datasource.
+ * Be sure to check the error field before invaidating the state.
+ *
+ * Returns: 0
+ */
+static int
+et_ogg_close_func (void *datasource)
+{
+ EtOggState *state = (EtOggState *)datasource;
+
+ g_clear_object (&state->file);
+ g_clear_object (&state->istream);
+ g_clear_error (&state->error);
+
+ return 0;
+}
+
+/*
+ * et_ogg_tell_func:
+ * @datasource: the Ogg parser state
+ *
+ * Tell the current position of the stream from the beginning of the Ogg file.
+ *
+ * Returns: the current position in the Ogg file
+ */
+static long
+et_ogg_tell_func (void *datasource)
+{
+ EtOggState *state = (EtOggState *)datasource;
+
+ return g_seekable_tell (G_SEEKABLE (state->istream));
+}
+
+gboolean
+Ogg_Header_Read_File_Info (const gchar *filename, ET_File_Info *ETFileInfo)
{
- FILE *file;
OggVorbis_File vf;
vorbis_info *vi;
gint encoder_version = 0;
@@ -70,21 +206,31 @@ gboolean Ogg_Header_Read_File_Info (gchar *filename, ET_File_Info *ETFileInfo)
glong bitrate_nominal = 0;
gdouble duration = 0;
gulong filesize;
- gint ret;
+ gint res;
+ ov_callbacks callbacks = { et_ogg_read_func, et_ogg_seek_func,
+ et_ogg_close_func, et_ogg_tell_func };
+ EtOggState state;
gchar *filename_utf8;
g_return_val_if_fail (filename != NULL && ETFileInfo != NULL, FALSE);
- filename_utf8 = filename_to_display(filename);
+ state.file = g_file_new_for_path (filename);
+ state.error = NULL;
+ state.istream = G_INPUT_STREAM (g_file_read (state.file, NULL,
+ &state.error));
+
+ filename_utf8 = filename_to_display (filename);
- if ( (file=fopen(filename,"rb"))==NULL ) // Warning : it is important to open the file in binary mode!
(to get header information under Win32)
+ if (!state.istream)
{
- Log_Print(LOG_ERROR,_("Error while opening file: '%s' (%s)."),filename_utf8,g_strerror(errno));
- g_free(filename_utf8);
+ /* FIXME: Pass error back to calling function. */
+ Log_Print (LOG_ERROR, _("Error while opening file: '%s' (%s)"),
+ filename_utf8, state.error->message);
+ g_free (filename_utf8);
return FALSE;
}
- if ( (ret=ov_open(file,&vf,NULL,0)) == 0)
+ if ((res = ov_open_callbacks (&state, &vf, NULL, 0, callbacks)) == 0)
{
if ( (vi=ov_info(&vf,0)) != NULL )
{
@@ -118,11 +264,16 @@ gboolean Ogg_Header_Read_File_Info (gchar *filename, ET_File_Info *ETFileInfo)
ov_clear(&vf); // This close also the file
}else
{
- // Because not closed by ov_clear()
- fclose(file);
+ /* On error. */
+ if (state.error)
+ {
+ g_debug ("Ogg Vorbis: error reading header information (%s)",
+ state.error->message);
+ }
+
+ et_ogg_close_func (&state);
- // On error...
- switch (ret)
+ switch (res)
{
case OV_EREAD:
Log_Print(LOG_ERROR,_("Ogg Vorbis: Read from media returned an error (file:
'%s')."),filename_utf8);
diff --git a/src/ogg_header.h b/src/ogg_header.h
index c35c36c..0817a31 100644
--- a/src/ogg_header.h
+++ b/src/ogg_header.h
@@ -76,7 +76,8 @@ typedef enum
* Prototypes *
**************/
-gboolean Ogg_Header_Read_File_Info (gchar *filename, ET_File_Info *ETFileInfo);
+gboolean Ogg_Header_Read_File_Info (const gchar *filename,
+ ET_File_Info *ETFileInfo);
gboolean Ogg_Header_Display_File_Info_To_UI (gchar *filename, ET_File_Info *ETFileInfo);
gboolean Speex_Header_Read_File_Info (gchar *filename, ET_File_Info *ETFileInfo);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]