[PATCH 1/3] Improve error handling in GIO/TagLib wrapper



Add some error checks and a method for getting the error to the GIO/TagLib
compatibility layer.
---
 src/gio_wrapper.cc | 269 +++++++++++++++++++++++++++++++++++++++++++++--------
 src/gio_wrapper.h  |   6 ++
 2 files changed, 237 insertions(+), 38 deletions(-)

diff --git a/src/gio_wrapper.cc b/src/gio_wrapper.cc
index db18305..b977e2a 100644
--- a/src/gio_wrapper.cc
+++ b/src/gio_wrapper.cc
@@ -19,16 +19,88 @@
 
 #include "gio_wrapper.h"
 
+template<class T> class SimpleAutoPtr
+{
+public:
+    SimpleAutoPtr (T *item, GDestroyNotify dest) : ptr(item), dtor(dest)
+    {
+    }
+
+    ~SimpleAutoPtr ()
+    {
+        clear ();
+    }
+
+    SimpleAutoPtr<T> &operator= (T *item)
+    {
+        clear ();
+        ptr = item;
+
+       return *this;
+    }
+
+    operator T * ()
+    {
+        return ptr;
+    }
+
+    operator GTypeInstance * ()
+    {
+        return (GTypeInstance *)ptr;
+    }
+
+    operator bool ()
+    {
+        return !!ptr;
+    }
+
+    T &operator* ()
+    {
+        return *ptr;
+    }
+
+    T **operator& ()
+    {
+        return &ptr;
+    }
+
+    T *operator-> ()
+    {
+        return ptr;
+    }
+
+    void clear ()
+    {
+        if (ptr)
+        {
+            dtor((void *)ptr);
+        }
+        ptr = NULL;
+    }
+
+private:
+    T *ptr;
+    GDestroyNotify dtor;
+};
+
 GIO_InputStream::GIO_InputStream (GFile * file_) :
     file ((GFile *)g_object_ref (gpointer (file_))),
-    filename (g_file_get_uri (file))
+    filename (g_file_get_uri (file)),
+    error (NULL)
 {
-    stream = g_file_read (file, NULL, NULL);
+    stream = g_file_read (file, NULL, &error);
 }
 
 GIO_InputStream::~GIO_InputStream ()
 {
-    g_input_stream_close (G_INPUT_STREAM (stream), NULL, NULL);
+    clear ();
+
+    if (stream)
+    {
+        g_input_stream_close (G_INPUT_STREAM (stream), NULL, &error);
+        clear ();
+    }
+
     g_free (filename);
     g_object_unref (G_OBJECT (file));
 }
@@ -42,12 +114,19 @@ GIO_InputStream::name () const
 TagLib::ByteVector
 GIO_InputStream::readBlock (ulong length)
 {
+    if (error)
+    {
+        return TagLib::ByteVector::null;
+    }
+
     TagLib::ByteVector rv (length, 0);
-    rv = rv.mid (0, g_input_stream_read (G_INPUT_STREAM (stream),
-                                         (void *)rv.data (), length, NULL,
-                                         NULL));
+    gsize bytes;
+    g_input_stream_read_all (G_INPUT_STREAM (stream),
+                             (void *)rv.data (), length,
+                             &bytes,
+                             NULL, &error);
 
-    return rv;
+    return rv.resize(bytes);
 }
 
 void
@@ -83,6 +162,11 @@ GIO_InputStream::isOpen () const
 void
 GIO_InputStream::seek (long int offset, TagLib::IOStream::Position p)
 {
+    if (error)
+    {
+        return;
+    }
+
     GSeekType type;
 
     switch (p)
@@ -101,12 +185,17 @@ GIO_InputStream::seek (long int offset, TagLib::IOStream::Position p)
             return;
     }
 
-    g_seekable_seek (G_SEEKABLE (stream), offset, type, NULL, NULL);
+    g_seekable_seek (G_SEEKABLE (stream), offset, type, NULL, &error);
 }
 
 void
 GIO_InputStream::clear ()
 {
+    if (error)
+    {
+        g_error_free(error);
+        error = NULL;
+    }
 }
 
 long int
@@ -118,12 +207,20 @@ GIO_InputStream::tell () const
 long int
 GIO_InputStream::length ()
 {
-    long rv;
+    if (error)
+    {
+        return -1;
+    }
+
+    long int rv = -1;
     GFileInfo *info = g_file_input_stream_query_info (stream,
                                                       G_FILE_ATTRIBUTE_STANDARD_SIZE,
-                                                      NULL, NULL);
-    rv = g_file_info_get_size (info);
-    g_object_unref (info);
+                                                      NULL, &error);
+    if (info)
+    {
+        rv = g_file_info_get_size (info);
+        g_object_unref (info);
+    }
 
     return rv;
 }
@@ -136,14 +233,28 @@ GIO_InputStream::truncate (long int length)
 
 GIO_IOStream::GIO_IOStream (GFile *file_) :
     file ((GFile *)g_object_ref (gpointer (file_))),
-    filename (g_file_get_uri (file_))
+    filename (g_file_get_uri (file_)),
+    error (NULL)
 {
-    stream = g_file_open_readwrite (file, NULL, NULL);
+    stream = g_file_open_readwrite (file, NULL, &error);
+}
+
+const GError *
+GIO_InputStream::getError () const
+{
+    return error;
 }
 
 GIO_IOStream::~GIO_IOStream ()
 {
-    g_io_stream_close (G_IO_STREAM (stream), NULL, NULL);
+    clear ();
+
+    if (stream)
+    {
+        g_io_stream_close (G_IO_STREAM (stream), NULL, &error);
+        clear ();
+    }
+
     g_free (filename);
     g_object_unref (G_OBJECT (file));
 }
@@ -157,19 +268,34 @@ GIO_IOStream::name () const
 TagLib::ByteVector
 GIO_IOStream::readBlock (ulong length)
 {
+    if (error)
+    {
+        return TagLib::ByteVector::null;
+    }
+
+    gsize bytes = 0;
     TagLib::ByteVector rv (length, 0);
     GInputStream *istream = g_io_stream_get_input_stream (G_IO_STREAM (stream));
-    rv = rv.mid (0, g_input_stream_read (istream, (void *)rv.data (), length,
-                                         NULL, NULL));
+    g_input_stream_read_all (istream,
+                             (void *)rv.data (), length,
+                             &bytes,
+                             NULL, &error);
 
-    return rv;
+    return rv.resize(bytes);
 }
 
 void
 GIO_IOStream::writeBlock (TagLib::ByteVector const &data)
 {
+    if (error)
+    {
+        return;
+    }
+
     GOutputStream *ostream = g_io_stream_get_output_stream (G_IO_STREAM (stream));
-    g_output_stream_write (ostream, data.data (), data.size (), NULL, NULL);
+
+    g_output_stream_write_all (ostream, data.data (), data.size (), NULL,
+                              NULL, &error);
 }
 
 void
@@ -177,6 +303,11 @@ GIO_IOStream::insert (TagLib::ByteVector const &data,
                       ulong start,
                       ulong replace)
 {
+    if (error)
+    {
+        return;
+    }
+
     if (data.size () == replace)
     {
         seek (start, TagLib::IOStream::Beginning);
@@ -191,10 +322,11 @@ GIO_IOStream::insert (TagLib::ByteVector const &data,
         return;
     }
 
-    GFileIOStream *tstr;
-    GFile *tmp = g_file_new_tmp ("easytag-XXXXXX", &tstr, NULL);
+    SimpleAutoPtr<GFileIOStream> tstr(NULL, (GDestroyNotify)g_io_stream_close);
+    SimpleAutoPtr<GFile> tmp(g_file_new_tmp("easytag-XXXXXX", &tstr, NULL), g_object_unref);
     char *buffer[4096];
     gsize r;
+
     GOutputStream *ostream = g_io_stream_get_output_stream (G_IO_STREAM (tstr));
     GInputStream *istream = g_io_stream_get_input_stream (G_IO_STREAM (stream));
 
@@ -202,48 +334,76 @@ GIO_IOStream::insert (TagLib::ByteVector const &data,
 
     while (g_input_stream_read_all (istream, buffer,
                                     MIN (sizeof (buffer), start), &r, NULL,
-                                    NULL) && r > 0)
+                                    &error) && r > 0)
     {
         gsize w;
-        g_output_stream_write_all (ostream, buffer, r, &w, NULL, NULL);
+        g_output_stream_write_all (ostream, buffer, r, &w, NULL, &error);
 
         if (w != r)
         {
             g_warning ("%s", "Unable to write all bytes");
         }
 
+       if (error)
+       {
+            return;
+       }
+
         start -= r;
         g_warning ("Wrote %lu bytees of %lu: %.*s", r, start, (int)r, buffer);
     }
 
-    g_output_stream_write (ostream, data.data (), data.size (), NULL, NULL);
+    if (error)
+    {
+        return;
+    }
+
+    g_output_stream_write_all (ostream, data.data (), data.size (), NULL,
+                               NULL, &error);
     seek (replace, TagLib::IOStream::Current);
 
+    if (error)
+    {
+        return;
+    }
+
     while (g_input_stream_read_all (istream, buffer, sizeof (buffer), &r,
-                                    NULL, NULL) && r > 0)
+                                    NULL, &error) && r > 0)
     {
         gsize w;
-        g_output_stream_write_all (ostream, buffer, r, &w, NULL, NULL);
+        g_output_stream_write_all (ostream, buffer, r, &w, NULL, &error);
 
         if (w != r)
         {
             g_warning ("%s", "Unable to write all bytes");
         }
+
+        if (error)
+        {
+            return;
+        }
     }
 
-    g_io_stream_close (G_IO_STREAM (tstr), NULL, NULL);
+    tstr = NULL;
     g_io_stream_close (G_IO_STREAM (stream), NULL, NULL);
-    g_file_move (tmp, file, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, NULL);
-    g_object_unref (gpointer(tmp));
-    stream = g_file_open_readwrite (file, NULL, NULL);
+    stream = NULL;
+
+    g_file_move (tmp, file, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &error);
+
+    if (error)
+    {
+           return;
+    }
+
+    stream = g_file_open_readwrite (file, NULL, &error);
 }
 
 void
 GIO_IOStream::removeBlock (ulong start, ulong len)
 {
-    if (start + len >= (ulong)length ())
+    if (start + len >= (ulong)length())
     {
-        truncate (start);
+        truncate(start);
         return;
     }
 
@@ -265,6 +425,11 @@ GIO_IOStream::removeBlock (ulong start, ulong len)
             g_warning ("%s", "Unable to write all bytes");
         }
 
+       if (error)
+       {
+           return;
+       }
+
         start += r;
         seek (start + len);
     }
@@ -287,6 +452,10 @@ GIO_IOStream::isOpen () const
 void
 GIO_IOStream::seek (long int offset, TagLib::IOStream::Position p)
 {
+    if (error)
+    {
+        return;
+    }
     GSeekType type;
 
     switch (p)
@@ -305,12 +474,17 @@ GIO_IOStream::seek (long int offset, TagLib::IOStream::Position p)
             return;
     }
 
-    g_seekable_seek (G_SEEKABLE (stream), offset, type, NULL, NULL);
+    g_seekable_seek (G_SEEKABLE (stream), offset, type, NULL, &error);
 }
 
 void
 GIO_IOStream::clear ()
 {
+    if (error)
+    {
+        g_error_free(error);
+        error = NULL;
+    }
 }
 
 long int
@@ -322,12 +496,21 @@ GIO_IOStream::tell () const
 long int
 GIO_IOStream::length ()
 {
-    long rv;
+    if (error)
+    {
+       return -1;
+    }
+
+    long rv = -1;
     GFileInfo *info = g_file_io_stream_query_info (stream,
                                                    G_FILE_ATTRIBUTE_STANDARD_SIZE,
-                                                   NULL, NULL);
-    rv = g_file_info_get_size (info);
-    g_object_unref (info);
+                                                   NULL, &error);
+
+    if (info)
+    {
+        rv = g_file_info_get_size (info);
+        g_object_unref (info);
+    }
 
     return rv;
 }
@@ -335,5 +518,15 @@ GIO_IOStream::length ()
 void
 GIO_IOStream::truncate (long int length)
 {
-    g_seekable_truncate (G_SEEKABLE (stream), length, NULL, NULL);
+    if (error)
+    {
+        return;
+    }
+
+    g_seekable_truncate (G_SEEKABLE (stream), length, NULL, &error);
+}
+
+const GError *GIO_IOStream::getError () const
+{
+    return error;
 }
diff --git a/src/gio_wrapper.h b/src/gio_wrapper.h
index d6f1b76..cd7f61d 100644
--- a/src/gio_wrapper.h
+++ b/src/gio_wrapper.h
@@ -41,11 +41,14 @@ public:
     virtual long int length ();
     virtual void truncate (long int length);
 
+    virtual const GError *getError() const;
+
 private:
     GIO_InputStream (const GIO_InputStream &other);
     GFile *file;
     GFileInputStream *stream;
     char *filename;
+    GError *error;
 };
 
 class GIO_IOStream : public TagLib::IOStream
@@ -66,11 +69,14 @@ public:
     virtual long int length ();
     virtual void truncate (long int length);
 
+    virtual const GError *getError() const;
+
 private:
     GIO_IOStream (const GIO_IOStream &other);
     GFile *file;
     GFileIOStream *stream;
     char *filename;
+    GError *error;
 };
 
 #endif /* ET_GIO_WRAPPER_H_ */
-- 
1.8.3.2



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