[gexiv2] Add GIO read-only support to Metadata
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gexiv2] Add GIO read-only support to Metadata
- Date: Tue, 1 Jan 2019 16:24:30 +0000 (UTC)
commit b1795fe1585351d3086373aaf12dd1c146c44c4d
Author: Jens Georg <mail jensge org>
Date: Tue Jun 19 13:23:51 2018 +0200
Add GIO read-only support to Metadata
Partial fix for #15
gexiv2/gexiv2-metadata.cpp | 194 +++++++++++++++++++++++++++++++++++++++++++++
gexiv2/gexiv2-metadata.h | 11 +++
gexiv2/meson.build | 6 +-
meson.build | 1 +
test/gexiv2-dump.vala | 4 +-
test/meson.build | 2 +-
6 files changed, 213 insertions(+), 5 deletions(-)
---
diff --git a/gexiv2/gexiv2-metadata.cpp b/gexiv2/gexiv2-metadata.cpp
index 83ec604..bb8a50f 100644
--- a/gexiv2/gexiv2-metadata.cpp
+++ b/gexiv2/gexiv2-metadata.cpp
@@ -31,6 +31,185 @@ using image_ptr = Exiv2::Image::UniquePtr;
using image_ptr = Exiv2::Image::AutoPtr;
#endif
+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)
+ , _error{nullptr}
+ , _eof{false}
+ {}
+
+ ~GioIo() { g_clear_object (&_is); g_clear_error (&_error); _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;
+ }
+
+ // Writing is not supported
+ 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{rcount};
+
+ long bytes_read = this->read(b.pData_, rcount);
+ if (bytes_read > 0 && bytes_read != rcount) {
+ b.reset({b.pData_, bytes_read});
+ }
+
+ 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) {
+ g_critical ("Error reading from stream: %d %s", error->code, error->message);
+ g_clear_error (&_error);
+ _error = error;
+
+ throw Exiv2::Error(2);
+ return 0;
+ }
+
+ if (result == 0) {
+ _eof = true;
+ } else {
+ _eof = false;
+ }
+
+ return result;
+ }
+
+ int getb() {
+ Exiv2::byte b;
+ return this->read (&b, 1) == 1 ? b : EOF;
+ }
+
+ void transfer(Exiv2::BasicIo &src) {
+ // Does not seem necessary for Read-only support
+ }
+
+ 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_clear_error(&_error);
+ g_critical ("Failed to seek: %s", error->message);
+ _error = 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_clear_error(&_error);
+ _error = error;
+ g_critical("Failed to seek forward: %s", error->message);
+
+ return -1;
+ }
+
+ return 0;
+ }
+ }
+
+ Exiv2::byte *mmap(bool writable) {
+ return NULL;
+ }
+
+ int munmap() {
+ return 0;
+ }
+
+ long tell() const {
+ if (_seekable != NULL && g_seekable_can_seek (_seekable)) {
+ return static_cast<long>(g_seekable_tell (_seekable));
+ } else {
+ return -1;
+ }
+ }
+
+ size_t size() const {
+ return -1;
+ }
+
+ bool isopen() const {
+ return true;
+ }
+
+ int error() const {
+ return _error == nullptr ? 0 : 1;
+ }
+
+ bool eof() const {
+ return _eof;
+ }
+
+ std::string path() const {
+ return "GIO Wrapper";
+ }
+
+#if EXIV2_TEST_VERSION(0,27,99)
+ Exiv2::BasicIo::UniquePtr temporary() const {
+ return Exiv2::BasicIo::UniquePtr(nullptr);
+ }
+#else
+ Exiv2::BasicIo::AutoPtr temporary() const {
+ return Exiv2::BasicIo::AutoPtr(nullptr);
+ }
+#endif
+
+
+private:
+ GInputStream *_is;
+ GSeekable *_seekable;
+ GError *_error;
+ bool _eof;
+}; // class GioIo
+} // Anonymous namespace
+
G_BEGIN_DECLS
G_DEFINE_TYPE_WITH_CODE (GExiv2Metadata, gexiv2_metadata, G_TYPE_OBJECT, G_ADD_PRIVATE (GExiv2Metadata));
@@ -205,6 +384,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..54e0e91 100644
--- a/gexiv2/gexiv2-metadata.h
+++ b/gexiv2/gexiv2-metadata.h
@@ -252,6 +252,17 @@ gboolean gexiv2_metadata_open_buf (GExiv2Metadata
*self, const guint8 *data,
*/
gboolean gexiv2_metadata_open_stream (GExiv2Metadata *self,
ManagedStreamCallbacks* cb, GError **error);
+
+/**
+ * gexiv2_metadata_from_stream:
+ * @self: An instance of #GExiv2Metadata
+ * @stream: A #GInputStream to get meta-data from
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Read meta-data from a GIO stream
+ */
+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 579905f..a7de975 100644
--- a/meson.build
+++ b/meson.build
@@ -12,6 +12,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]