[gexiv2/wip/phako/gio: 25/27] wip: Add GIO support to Metadata



commit a049215519bb538149a77e2d606b1e7edc231a95
Author: Jens Georg <mail jensge org>
Date:   Tue Jun 19 13:23:51 2018 +0200

    wip: Add GIO support to Metadata
    
    Work in progress.  Read-only support.
    
    Fixes #15

 gexiv2/gexiv2-metadata.cpp | 166 +++++++++++++++++++++++++++++++++++++++++++++
 gexiv2/gexiv2-metadata.h   |   2 +
 gexiv2/meson.build         |   6 +-
 meson.build                |   1 +
 test/gexiv2-dump.vala      |   4 +-
 test/meson.build           |   2 +-
 6 files changed, 176 insertions(+), 5 deletions(-)
---
diff --git a/gexiv2/gexiv2-metadata.cpp b/gexiv2/gexiv2-metadata.cpp
index 9c791ef..683c82d 100644
--- a/gexiv2/gexiv2-metadata.cpp
+++ b/gexiv2/gexiv2-metadata.cpp
@@ -25,6 +25,157 @@
 
 #include <exiv2/exiv2.hpp>
 
+namespace {
+class GioIo : public Exiv2::BasicIo {
+public:
+    GioIo (GInputStream *is)
+        : BasicIo ()
+        , _is (G_INPUT_STREAM (g_object_ref (is)))
+        , _seekable(G_IS_SEEKABLE(_is) ? G_SEEKABLE (_is) : NULL) {}
+
+    ~GioIo() { g_clear_object (&_is); _seekable = NULL;}
+#if defined(_MSC_VER)
+    typedef int64_t seek_offset_t;
+#else
+    typedef long seek_offset_t;
+#endif
+
+    int open() { return 0; }
+    int close() { return 0; }
+    long write(const Exiv2::byte *data, long wcount) { return 0; }
+    long write(BasicIo &src) { return 0; }
+    int putb(Exiv2::byte data) { return EOF; }
+
+    Exiv2::DataBuf read(long rcount) {
+        Exiv2::DataBuf b;
+        Exiv2::byte *buf = new Exiv2::byte[rcount];
+
+        long bytes_read = this->read(buf, rcount);
+        if (bytes_read > 0) {
+            b.alloc(bytes_read);
+            memcpy(b.pData_, buf, bytes_read);
+        }
+
+        delete[] buf;
+
+        return b;
+    }
+
+    long read(Exiv2::byte *buf, long rcount) {
+        GError *error = NULL;
+        gssize result = 0;
+
+        result = g_input_stream_read(_is, reinterpret_cast<void *>(buf), rcount, NULL, &error);
+        if (error != NULL) {
+            throw Exiv2::Error(2);
+            return 0;
+        }
+
+        return result;
+    }
+
+    int getb() {
+        Exiv2::byte b;
+        return this->read (&b, 1) == 1 ? b : EOF;
+    }
+
+    void transfer(Exiv2::BasicIo &src) {
+        // TODO: Implement
+    }
+
+    int seek(seek_offset_t offset, Exiv2::BasicIo::Position position) {
+        if (_seekable != NULL && g_seekable_can_seek (_seekable)) {
+            GSeekType t = G_SEEK_SET;
+            switch (position) {
+                case Exiv2::BasicIo::cur:
+                    t = G_SEEK_CUR;
+                    break;
+                case Exiv2::BasicIo::beg:
+                    t = G_SEEK_SET;
+                    break;
+                case Exiv2::BasicIo::end:
+                    t = G_SEEK_END;
+                    break;
+                default:
+                    g_assert_not_reached ();
+                    break;
+            }
+
+            GError *error = NULL;
+            g_seekable_seek (_seekable, offset, t, NULL, &error);
+            if (error != NULL) {
+                g_critical ("Failed to seek: %s", error->message);
+
+                g_error_free (error);
+
+                return -1;
+            }
+
+            return 0;
+        } else {
+            // Can only seek forward here...
+            if (position != Exiv2::BasicIo::cur) {
+                return -1;
+            }
+
+            GError *error = NULL;
+            g_input_stream_skip (_is, offset, NULL, &error);
+            if (error != NULL) {
+                g_critical("Failed to seek forward: %s", error->message);
+
+                g_error_free(error);
+
+                return -1;
+            }
+
+            return 0;
+        }
+    }
+
+    Exiv2::byte *mmap(bool writable) {
+        return NULL;
+    }
+
+    int munmap() {
+        return 0;
+    }
+
+    long tell() const {
+        return -1;
+    }
+
+    long size() const {
+        return -1;
+    }
+
+    bool isopen() const {
+        return true;
+    }
+
+    int error() const {
+        return 0;
+    }
+
+    bool eof() const {
+        return false;
+    }
+
+    std::string path() const {
+        return "GIO Wrapper";
+    }
+
+    Exiv2::BasicIo::AutoPtr temporary() const {
+        return Exiv2::BasicIo::AutoPtr(new Exiv2::FileIo("/tmp/exiv2-temp"));
+    }
+
+
+private:
+    GInputStream *_is;
+    GSeekable *_seekable;
+
+
+}; // class GioIo
+} // Anonymous namespace
 
 G_BEGIN_DECLS
 
@@ -197,6 +348,21 @@ gboolean gexiv2_metadata_open_stream (GExiv2Metadata *self, ManagedStreamCallbac
     return FALSE;
 }
 
+gboolean gexiv2_metadata_from_stream(GExiv2Metadata *self, GInputStream *stream, GError **error) {
+    g_return_val_if_fail (GEXIV2_IS_METADATA (self), FALSE);
+
+    try {
+        Exiv2::BasicIo::AutoPtr gio_ptr (new GioIo (stream));
+        self->priv->image = Exiv2::ImageFactory::open (gio_ptr);
+
+        return gexiv2_metadata_open_internal (self, error);
+    } catch (Exiv2::Error &e) {
+        g_set_error_literal (error, g_quark_from_string ("GExiv2"), e.code(), e.what());
+    }
+
+    return FALSE;
+}
+
 // Exiv2 does not today offer a clean way to decode a buffer with only the JFIF APP1 segment,
 // where EXIF lives.  This is a common situation when reading EXIF metadata straight from a
 // camera (i.e. via gPhoto) where accessing the entire JPEG image is inconvenient.
diff --git a/gexiv2/gexiv2-metadata.h b/gexiv2/gexiv2-metadata.h
index 1b21c0e..035094c 100644
--- a/gexiv2/gexiv2-metadata.h
+++ b/gexiv2/gexiv2-metadata.h
@@ -252,6 +252,8 @@ gboolean            gexiv2_metadata_open_buf                        (GExiv2Metadata 
*self, const guint8 *data,
  */
 gboolean               gexiv2_metadata_open_stream                     (GExiv2Metadata *self, 
ManagedStreamCallbacks* cb, GError **error);
 
+gboolean               gexiv2_metadata_from_stream                     (GExiv2Metadata *self, GInputStream* 
stream, GError **error);
+
 /**
  * gexiv2_metadata_from_app1_segment:
  * @self: An instance of #GExiv2Metadata
diff --git a/gexiv2/meson.build b/gexiv2/meson.build
index 85da997..2ccae82 100644
--- a/gexiv2/meson.build
+++ b/gexiv2/meson.build
@@ -63,7 +63,7 @@ gexiv2 = library('gexiv2',
                  link_args : vflag,
                  include_directories : include_directories('..'),
                  version: '2.0.0',
-                 dependencies : [gobject, exiv2],
+                 dependencies : [gobject, exiv2, gio],
                  install : true)
 
 libgexiv2 = declare_dependency(
@@ -72,7 +72,7 @@ libgexiv2 = declare_dependency(
     dependencies : [gobject, exiv2],
 )
 
-pc_deps = ['glib-2.0', 'gobject-2.0']
+pc_deps = ['glib-2.0', 'gobject-2.0', 'gio-2.0']
 
 pkg.generate(
     description : 'GObject bindings for exiv2',
@@ -102,7 +102,7 @@ if introspection_available
       symbol_prefix : 'gexiv2',
       identifier_prefix : 'GExiv2',
       export_packages : 'gexiv2',
-      includes : ['GObject-2.0'],
+      includes : ['GObject-2.0', 'Gio-2.0'],
       header : 'gexiv2/gexiv2.h',
       install : true)
 
diff --git a/meson.build b/meson.build
index 0430365..f782f48 100644
--- a/meson.build
+++ b/meson.build
@@ -4,6 +4,7 @@ pkg = import('pkgconfig')
 
 exiv2 = dependency('exiv2', version : '>= 0.26')
 gobject = dependency('gobject-2.0', version : '>= 2.38.0')
+gio = dependency('gio-2.0', version : '>= 2.32.0')
 
 gir = find_program('g-ir-scanner', required: false)
 vapigen = find_program('vapigen', required: false)
diff --git a/test/gexiv2-dump.vala b/test/gexiv2-dump.vala
index 7bf6ef3..0dc7724 100644
--- a/test/gexiv2-dump.vala
+++ b/test/gexiv2-dump.vala
@@ -18,7 +18,9 @@ int main(string[] args) {
     foreach (string filename in args[1:args.length]) {
         try {
             GExiv2.Metadata metadata = new GExiv2.Metadata();
-            metadata.open_path(filename);
+//            metadata.open_path(filename);
+            var file = File.new_for_path (filename);
+            metadata.from_stream (file.read ());
             
             dump_tags(metadata, metadata.get_exif_tags());
             dump_tags(metadata, metadata.get_iptc_tags());
diff --git a/test/meson.build b/test/meson.build
index 50593b8..f3cc10a 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -23,7 +23,7 @@ if vapi_available
     executable('gexiv2-dump',
                'gexiv2-dump.vala',
                include_directories : include_directories('..'),
-               dependencies : [gobject, vapi],
+               dependencies : [gobject, vapi, gio],
                link_with : gexiv2)
   endif
 endif


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