[PATCH 1/2] 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 | 294 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/gio_wrapper.h  |  76 ++++++++++++++
 3 files changed, 372 insertions(+)
 create mode 100644 src/gio_wrapper.cc
 create mode 100644 src/gio_wrapper.h

diff --git a/Makefile.am b/Makefile.am
index 0bdcf00..704c694 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -51,6 +51,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 \
@@ -91,6 +92,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..826a978
--- /dev/null
+++ b/src/gio_wrapper.cc
@@ -0,0 +1,294 @@
+/*
+ *  EasyTAG - Tag editor for MP3 and Ogg Vorbis 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 ("Trying to write to read-only file!");
+}
+
+void GIO_InputStream::insert (TagLib::ByteVector const &data, ulong start, ulong replace)
+{
+    g_warning ("Trying to write to read-only file!");
+}
+
+void GIO_InputStream::removeBlock (ulong start, ulong length)
+{
+    g_warning ("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 ("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 ("Unable to write all bytes");
+        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);
+    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 ("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("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 ("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..c9ac088
--- /dev/null
+++ b/src/gio_wrapper.h
@@ -0,0 +1,76 @@
+/*
+ *  EasyTAG - Tag editor for MP3 and Ogg Vorbis 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 GIO_WRAPPER_H
+#define 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
-- 
1.8.3.2



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