[easytag/wip/help: 10/18] Add GIO/TagLib compatibility layer



commit 44ee383fb2d981c165c72e3d962df0a6dd131add
Author: Santtu Lakkala <inz inz fi>
Date:   Thu Apr 10 11:01:52 2014 +0300

    Add GIO/TagLib compatibility layer
    
    Create GIO based implementations of TagLib::IOStream, so TagLib can be used
    over GIO. The implementation still lacks almost all error handling, but works
    in normal situations.

 Makefile.am        |    2 +
 src/gio_wrapper.cc |  339 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/gio_wrapper.h  |   76 ++++++++++++
 3 files changed, 417 insertions(+), 0 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index f090579..1f58f47 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -52,6 +52,7 @@ easytag_SOURCES = \
        src/et_core.c \
        src/flac_header.c \
        src/flac_tag.c \
+       src/gio_wrapper.cc \
        src/gtk2_compat.c \
        src/id3_tag.c \
        src/id3v24_tag.c \
@@ -94,6 +95,7 @@ easytag_headers = \
        src/flac_header.h \
        src/flac_tag.h \
        src/genres.h \
+       src/gio_wrapper.h \
        src/gtk2_compat.h \
        src/id3_tag.h \
        src/log.h \
diff --git a/src/gio_wrapper.cc b/src/gio_wrapper.cc
new file mode 100644
index 0000000..e9cd0cd
--- /dev/null
+++ b/src/gio_wrapper.cc
@@ -0,0 +1,339 @@
+/*
+ *  EasyTAG - Tag editor for audio files
+ *  Copyright (C) 2014  Santtu Lakkala <inz inz fi>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "gio_wrapper.h"
+
+GIO_InputStream::GIO_InputStream (GFile * file_) :
+    file ((GFile *)g_object_ref (gpointer (file_))),
+    filename (g_file_get_uri (file))
+{
+    stream = g_file_read (file, NULL, NULL);
+}
+
+GIO_InputStream::~GIO_InputStream ()
+{
+    g_input_stream_close (G_INPUT_STREAM (stream), NULL, NULL);
+    g_free (filename);
+    g_object_unref (G_OBJECT (file));
+}
+
+TagLib::FileName
+GIO_InputStream::name () const
+{
+    return TagLib::FileName (filename);
+}
+
+TagLib::ByteVector
+GIO_InputStream::readBlock (ulong length)
+{
+    TagLib::ByteVector rv (length, 0);
+    rv = rv.mid (0, g_input_stream_read (G_INPUT_STREAM (stream),
+                                         (void *)rv.data (), length, NULL,
+                                         NULL));
+
+    return rv;
+}
+
+void
+GIO_InputStream::writeBlock (TagLib::ByteVector const &data)
+{
+    g_warning ("%s", "Trying to write to read-only file!");
+}
+
+void
+GIO_InputStream::insert (TagLib::ByteVector const &data, ulong start, ulong replace)
+{
+    g_warning ("%s", "Trying to write to read-only file!");
+}
+
+void
+GIO_InputStream::removeBlock (ulong start, ulong length)
+{
+    g_warning ("%s", "Trying to write to read-only file!");
+}
+
+bool
+GIO_InputStream::readOnly () const
+{
+    return true;
+}
+
+bool
+GIO_InputStream::isOpen () const
+{
+    return !!stream;
+}
+
+void
+GIO_InputStream::seek (long int offset, TagLib::IOStream::Position p)
+{
+    GSeekType type;
+
+    switch (p)
+    {
+        case TagLib::IOStream::Beginning:
+            type = G_SEEK_SET;
+            break;
+        case TagLib::IOStream::Current:
+            type = G_SEEK_CUR;
+            break;
+        case TagLib::IOStream::End:
+            type = G_SEEK_END;
+            break;
+        default:
+            g_warning ("Unknown seek");
+            return;
+    }
+
+    g_seekable_seek (G_SEEKABLE (stream), offset, type, NULL, NULL);
+}
+
+void
+GIO_InputStream::clear ()
+{
+}
+
+long int
+GIO_InputStream::tell () const
+{
+    return g_seekable_tell (G_SEEKABLE (stream));
+}
+
+long int
+GIO_InputStream::length ()
+{
+    long rv;
+    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);
+
+    return rv;
+}
+
+void
+GIO_InputStream::truncate (long int length)
+{
+    g_warning ("%s", "Trying to truncate read-only file");
+}
+
+GIO_IOStream::GIO_IOStream (GFile *file_) :
+    file ((GFile *)g_object_ref (gpointer (file_))),
+    filename (g_file_get_uri (file_))
+{
+    stream = g_file_open_readwrite (file, NULL, NULL);
+}
+
+GIO_IOStream::~GIO_IOStream ()
+{
+    g_io_stream_close (G_IO_STREAM (stream), NULL, NULL);
+    g_free (filename);
+    g_object_unref (G_OBJECT (file));
+}
+
+TagLib::FileName
+GIO_IOStream::name () const
+{
+    return TagLib::FileName (filename);
+}
+
+TagLib::ByteVector
+GIO_IOStream::readBlock (ulong length)
+{
+    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));
+
+    return rv;
+}
+
+void
+GIO_IOStream::writeBlock (TagLib::ByteVector const &data)
+{
+    GOutputStream *ostream = g_io_stream_get_output_stream (G_IO_STREAM (stream));
+    g_output_stream_write (ostream, data.data (), data.size (), NULL, NULL);
+}
+
+void
+GIO_IOStream::insert (TagLib::ByteVector const &data,
+                      ulong start,
+                      ulong replace)
+{
+    if (data.size () == replace)
+    {
+        seek (start, TagLib::IOStream::Beginning);
+        writeBlock (data);
+        return;
+    }
+    else if (data.size () < replace)
+    {
+        removeBlock (start, replace - data.size ());
+        seek (start);
+        writeBlock (data);
+        return;
+    }
+
+    GFileIOStream *tstr;
+    GFile *tmp = g_file_new_tmp ("easytag-XXXXXX", &tstr, NULL);
+    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));
+
+    seek (0);
+
+    while (g_input_stream_read_all (istream, buffer,
+                                    MIN (sizeof (buffer), start), &r, NULL,
+                                    NULL) && r > 0)
+    {
+        gsize w;
+        g_output_stream_write_all (ostream, buffer, r, &w, NULL, NULL);
+
+        if (w != r)
+        {
+            g_warning ("%s", "Unable to write all bytes");
+        }
+
+        start -= r;
+        g_warning ("Wrote %lu bytes of %lu: %.*s", r, start, (int)r, buffer);
+    }
+
+    g_output_stream_write (ostream, data.data (), data.size (), NULL, NULL);
+    seek (replace, TagLib::IOStream::Current);
+
+    while (g_input_stream_read_all (istream, buffer, sizeof (buffer), &r,
+                                    NULL, NULL) && r > 0)
+    {
+        gsize w;
+        g_output_stream_write_all (ostream, buffer, r, &w, NULL, NULL);
+
+        if (w != r)
+        {
+            g_warning ("%s", "Unable to write all bytes");
+        }
+    }
+
+    g_io_stream_close (G_IO_STREAM (tstr), NULL, 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);
+}
+
+void
+GIO_IOStream::removeBlock (ulong start, ulong len)
+{
+    if (start + len >= (ulong)length ())
+    {
+        truncate (start);
+        return;
+    }
+
+    char *buffer[4096];
+    gsize r;
+    GInputStream *istream = g_io_stream_get_input_stream (G_IO_STREAM (stream));
+    GOutputStream *ostream = g_io_stream_get_output_stream (G_IO_STREAM (stream));
+    seek (start + len);
+
+    while (g_input_stream_read_all (istream, buffer, sizeof (buffer), &r, NULL,
+                                    NULL) && r > 0)
+    {
+        gsize w;
+        seek (start);
+        g_output_stream_write_all (ostream, buffer, r, &w, NULL, NULL);
+
+        if (w != r)
+        {
+            g_warning ("%s", "Unable to write all bytes");
+        }
+
+        start += r;
+        seek (start + len);
+    }
+
+    truncate (start);
+}
+
+bool
+GIO_IOStream::readOnly () const
+{
+    return !stream;
+}
+
+bool
+GIO_IOStream::isOpen () const
+{
+    return !!stream;
+}
+
+void
+GIO_IOStream::seek (long int offset, TagLib::IOStream::Position p)
+{
+    GSeekType type;
+
+    switch (p)
+    {
+        case TagLib::IOStream::Beginning:
+            type = G_SEEK_SET;
+            break;
+        case TagLib::IOStream::Current:
+            type = G_SEEK_CUR;
+            break;
+        case TagLib::IOStream::End:
+            type = G_SEEK_END;
+            break;
+        default:
+            g_warning ("%s", "Unknown seek");
+            return;
+    }
+
+    g_seekable_seek (G_SEEKABLE (stream), offset, type, NULL, NULL);
+}
+
+void
+GIO_IOStream::clear ()
+{
+}
+
+long int
+GIO_IOStream::tell () const
+{
+    return g_seekable_tell (G_SEEKABLE (stream));
+}
+
+long int
+GIO_IOStream::length ()
+{
+    long rv;
+    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);
+
+    return rv;
+}
+
+void
+GIO_IOStream::truncate (long int length)
+{
+    g_seekable_truncate (G_SEEKABLE (stream), length, NULL, NULL);
+}
diff --git a/src/gio_wrapper.h b/src/gio_wrapper.h
new file mode 100644
index 0000000..d6f1b76
--- /dev/null
+++ b/src/gio_wrapper.h
@@ -0,0 +1,76 @@
+/*
+ *  EasyTAG - Tag editor for audio files
+ *  Copyright (C) 2014  Santtu Lakkala <inz inz fi>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef ET_GIO_WRAPPER_H_
+#define ET_GIO_WRAPPER_H_
+
+#include <tiostream.h>
+#include <gio/gio.h>
+
+class GIO_InputStream : public TagLib::IOStream
+{
+public:
+    GIO_InputStream (GFile *file_);
+    virtual ~GIO_InputStream ();
+    virtual TagLib::FileName name () const;
+    virtual TagLib::ByteVector readBlock (ulong length);
+    virtual void writeBlock (TagLib::ByteVector const &data);
+    virtual void insert (TagLib::ByteVector const &data, ulong start = 0, ulong replace = 0);
+    virtual void removeBlock (ulong start = 0, ulong length = 0);
+    virtual bool readOnly () const;
+    virtual bool isOpen () const;
+    virtual void seek (long int offset, TagLib::IOStream::Position p = TagLib::IOStream::Beginning);
+    virtual void clear ();
+    virtual long int tell () const;
+    virtual long int length ();
+    virtual void truncate (long int length);
+
+private:
+    GIO_InputStream (const GIO_InputStream &other);
+    GFile *file;
+    GFileInputStream *stream;
+    char *filename;
+};
+
+class GIO_IOStream : public TagLib::IOStream
+{
+public:
+    GIO_IOStream (GFile *file_);
+    virtual ~GIO_IOStream ();
+    virtual TagLib::FileName name () const;
+    virtual TagLib::ByteVector readBlock (ulong length);
+    virtual void writeBlock (TagLib::ByteVector const &data);
+    virtual void insert (TagLib::ByteVector const &data, ulong start = 0, ulong replace = 0);
+    virtual void removeBlock (ulong start = 0, ulong len = 0);
+    virtual bool readOnly () const;
+    virtual bool isOpen () const;
+    virtual void seek (long int offset, TagLib::IOStream::Position p = TagLib::IOStream::Beginning);
+    virtual void clear ();
+    virtual long int tell () const;
+    virtual long int length ();
+    virtual void truncate (long int length);
+
+private:
+    GIO_IOStream (const GIO_IOStream &other);
+    GFile *file;
+    GFileIOStream *stream;
+    char *filename;
+};
+
+#endif /* ET_GIO_WRAPPER_H_ */


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