[gexiv2/wip/phako/gio: 12/12] wip: GIO write support
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gexiv2/wip/phako/gio: 12/12] wip: GIO write support
- Date: Sat, 19 Jan 2019 09:07:33 +0000 (UTC)
commit 49036260188bc6625e0636ab6f3308aa76586a58
Author: Jens Georg <mail jensge org>
Date: Wed Jan 2 15:58:08 2019 +0100
wip: GIO write support
gexiv2/gexiv2-metadata-gio.cpp | 333 +++++++++++++++++++++++++++++++++++++++++
gexiv2/gexiv2-metadata-gio.h | 165 ++++++++++++++++++++
gexiv2/gexiv2-metadata.cpp | 210 +++-----------------------
gexiv2/gexiv2-metadata.h | 12 ++
gexiv2/meson.build | 2 +
tools/gexiv2-copy.vala | 43 ++++++
tools/meson.build | 6 +
7 files changed, 581 insertions(+), 190 deletions(-)
---
diff --git a/gexiv2/gexiv2-metadata-gio.cpp b/gexiv2/gexiv2-metadata-gio.cpp
new file mode 100644
index 0000000..c30133b
--- /dev/null
+++ b/gexiv2/gexiv2-metadata-gio.cpp
@@ -0,0 +1,333 @@
+#include "gexiv2-metadata-gio.h"
+
+namespace GExiv2 {
+namespace Internal {
+GioIo::GioIo(GInputStream *is)
+ : BasicIo ()
+ , _is (G_INPUT_STREAM (g_object_ref (is)))
+ , _seekable(G_IS_SEEKABLE(_is) ? G_SEEKABLE (_is) : nullptr)
+ , _error{nullptr}
+ , _eof{false}
+{}
+
+GioIo::~GioIo()
+{
+ g_clear_object (&_is);
+ g_clear_error (&_error);
+ _seekable = nullptr;
+}
+
+int GioIo::open()
+{
+ g_debug ("%s", __PRETTY_FUNCTION__);
+ return this->seek(0, Exiv2::BasicIo::beg);
+}
+
+Exiv2::DataBuf GioIo::read(long rcount)
+{
+ g_debug ("%s", __PRETTY_FUNCTION__);
+ Exiv2::DataBuf b{rcount};
+
+ long bytes_read = this->read(b.pData_, rcount);
+ b.size_ = bytes_read;
+
+ return b;
+}
+
+long GioIo::read(Exiv2::byte *buf, long rcount)
+{
+ g_debug ("%s %ld", __PRETTY_FUNCTION__, 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;
+
+#if EXIV2_TEST_VERSION(0,27,0)
+ throw Exiv2::Error(Exiv2::ErrorCode::kerFailedToReadImageData);
+#else
+ throw Exiv2::Error(2);
+#endif
+ return 0;
+ }
+
+ if (result == 0) {
+ _eof = true;
+ } else {
+ _eof = false;
+ }
+
+ return result;
+}
+
+int GioIo::getb()
+{
+ g_debug ("%s", __PRETTY_FUNCTION__);
+ Exiv2::byte b;
+ return this->read (&b, 1) == 1 ? b : EOF;
+}
+
+int GioIo::seek(seek_offset_t offset, Exiv2::BasicIo::Position position)
+{
+ g_debug ("%s %ld %d", __PRETTY_FUNCTION__, offset, (int)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;
+ }
+}
+
+long GioIo::tell() const
+{
+ g_debug ("%s", __PRETTY_FUNCTION__);
+ if (_seekable != NULL && g_seekable_can_seek (_seekable)) {
+ return static_cast<long>(g_seekable_tell (_seekable));
+ } else {
+ return -1;
+ }
+}
+
+GioRwIo::GioRwIo(GIOStream *is)
+ : BasicIo ()
+ , _is (G_IO_STREAM (g_object_ref (is)))
+ , _seekable(G_IS_SEEKABLE(_is) ? G_SEEKABLE (_is) : nullptr)
+ , _error{nullptr}
+ , _eof{false}
+{
+ if (not _seekable) {
+ _seekable = G_SEEKABLE (g_io_stream_get_input_stream (_is));
+ }
+ g_debug ("%s %p", __PRETTY_FUNCTION__, _seekable);
+}
+
+GioRwIo::~GioRwIo()
+{
+ g_clear_object (&_is);
+ g_clear_error (&_error);
+ _seekable = nullptr;
+}
+
+int GioRwIo::open()
+{
+ g_output_stream_flush (g_io_stream_get_output_stream (_is), nullptr, nullptr);
+ return this->seek(0, Exiv2::BasicIo::beg);
+}
+
+int GioRwIo::close()
+{
+ g_output_stream_flush (g_io_stream_get_output_stream (_is), nullptr, nullptr);
+ return 0;
+}
+
+
+Exiv2::DataBuf GioRwIo::read(long rcount)
+{
+ g_debug ("%s %ld", __PRETTY_FUNCTION__, rcount);
+ Exiv2::DataBuf b{rcount};
+
+ long bytes_read = this->read(b.pData_, rcount);
+ b.size_ = bytes_read;
+
+ return b;
+}
+
+long GioRwIo::read(Exiv2::byte *buf, long rcount)
+{
+ g_debug ("%s %ld", __PRETTY_FUNCTION__, rcount);
+ GError *error = NULL;
+ gssize result = 0;
+ GInputStream *is = g_io_stream_get_input_stream (_is);
+
+ 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;
+
+#if EXIV2_TEST_VERSION(0,27,0)
+ throw Exiv2::Error(Exiv2::ErrorCode::kerFailedToReadImageData);
+#else
+ throw Exiv2::Error(2);
+#endif
+ return 0;
+ }
+
+ if (result == 0) {
+ _eof = true;
+ } else {
+ _eof = false;
+ }
+
+ return result;
+}
+
+int GioRwIo::getb()
+{
+ g_debug ("%s", __PRETTY_FUNCTION__);
+ Exiv2::byte b;
+ return this->read (&b, 1) == 1 ? b : EOF;
+}
+
+int GioRwIo::seek(seek_offset_t offset, Exiv2::BasicIo::Position position)
+{
+ g_debug ("%s %ld %d", __PRETTY_FUNCTION__, offset, (int)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;
+ auto r = g_seekable_seek (_seekable, offset, t, NULL, &error);
+ g_debug ("Seeking success: %d", r);
+ if (error != NULL) {
+ g_clear_error(&_error);
+ g_critical ("Failed to seek: %s", error->message);
+ _error = error;
+
+ return -1;
+ }
+
+ return 0;
+ } else {
+ g_warning ("No seekable!");
+ return -1;
+ }
+}
+
+long GioRwIo::tell() const
+{
+ g_debug ("%s", __PRETTY_FUNCTION__);
+ if (_seekable != NULL && g_seekable_can_seek (_seekable)) {
+ return static_cast<long>(g_seekable_tell (_seekable));
+ } else {
+ return -1;
+ }
+}
+
+long GioRwIo::write(const Exiv2::byte *data, long wcount)
+{
+ g_debug ("%s: %ld", __PRETTY_FUNCTION__, wcount);
+ return EOF;
+}
+
+long GioRwIo::write(BasicIo &src)
+{
+ g_debug ("%s", __PRETTY_FUNCTION__);
+ return 0;
+}
+
+int GioRwIo::putb(Exiv2::byte data)
+{
+ g_debug ("%s", __PRETTY_FUNCTION__);
+ return this->write(&data, 1);
+}
+
+void GioRwIo::transfer(Exiv2::BasicIo &src)
+{
+ g_debug ("%s %s %ld %ld ", __PRETTY_FUNCTION__,
+ typeid(src).name(),
+ src.size(),
+ src.tell());
+ GioRwIo *gio = dynamic_cast<GioRwIo *>(&src);
+ GError *error = nullptr;
+
+ // rewind everything
+ src.open();
+ this->open();
+ g_input_stream_close (g_io_stream_get_input_stream (_is), nullptr, &error);
+
+ if (gio != nullptr) {
+ // Shortcut, use GIO's stream splicing for this
+ g_output_stream_splice (g_io_stream_get_output_stream (_is),
+ g_io_stream_get_input_stream (gio->_is),
+ G_OUTPUT_STREAM_SPLICE_NONE,
+ nullptr,
+ &error);
+
+ if (error != nullptr) {
+ g_warning ("Failed to splice: %s", error->message);
+ g_clear_error (&_error);
+ _error = error;
+ }
+ } else {
+ auto os = g_io_stream_get_output_stream (_is);
+ while (not src.eof()) {
+ auto buf = src.read(4096);
+ if (buf.size_ > 0) {
+ g_debug ("Got %ld bytes, writing", buf.size_);
+ g_output_stream_write_all (os, buf.pData_, buf.size_, nullptr, nullptr, &error);
+ if (error != nullptr) {
+ g_warning ("Failed to write: %s", error->message);
+ g_clear_error (&_error);
+ _error = error;
+ break;
+ }
+ } else {
+ g_debug ("No more data");
+ break;
+ }
+ }
+ }
+ g_output_stream_flush (g_io_stream_get_output_stream (_is), nullptr, nullptr);
+}
+
+
+
+} // namespace Internal
+} // namespace GExiv2
diff --git a/gexiv2/gexiv2-metadata-gio.h b/gexiv2/gexiv2-metadata-gio.h
new file mode 100644
index 0000000..fe71428
--- /dev/null
+++ b/gexiv2/gexiv2-metadata-gio.h
@@ -0,0 +1,165 @@
+#ifndef GEXIV2_METADATA_GIO
+#define GEXIV2_METADATA_GIO
+
+#include <gio/gio.h>
+#include <exiv2/exiv2.hpp>
+
+namespace GExiv2 {
+namespace Internal {
+class GioIo : public Exiv2::BasicIo {
+public:
+ GioIo (GInputStream *is);
+ ~GioIo();
+
+#if defined(_MSC_VER)
+ using seek_offset_t = int64_t;
+#else
+ using seek_offset_t = long;
+#endif
+
+#if EXIV2_TEST_VERSION(0,27,99)
+ using ptr_type = Exiv2::BasicIo::UniquePtr;
+#else
+ using ptr_type = Exiv2::BasicIo::AutoPtr;
+#endif
+
+ int open() override;
+ int close() override { return 0; }
+
+ // Writing is not supported
+ long write(const Exiv2::byte *data, long wcount) override { return 0; }
+ long write(BasicIo &src) override { return 0; }
+ int putb(Exiv2::byte data) override { return EOF; }
+
+ Exiv2::DataBuf read(long rcount) override;
+ long read(Exiv2::byte *buf, long rcount) override ;
+ int getb() override;
+
+ // Does not seem necessary for Read-only support
+ void transfer(Exiv2::BasicIo &src) override { }
+
+ int seek(seek_offset_t offset, Exiv2::BasicIo::Position position) override;
+
+
+ // MMapping not supported
+ Exiv2::byte *mmap(bool writable) override { return nullptr; }
+ int munmap() override { return 0; }
+
+ long tell() const override;
+ // Cannot tell the size from a random stream - also it does not
+ // seem to be necessary for what we are doing
+ size_t size() const override { return -1; }
+
+ bool isopen() const override { return true; }
+
+ int error() const override { return _error == nullptr ? 0 : 1; }
+
+ bool eof() const override { 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
+
+class GioRwIo : public Exiv2::BasicIo {
+public:
+ GioRwIo (GIOStream *ios);
+ ~GioRwIo();
+
+#if defined(_MSC_VER)
+ using seek_offset_t = int64_t;
+#else
+ using seek_offset_t = long;
+#endif
+
+#if EXIV2_TEST_VERSION(0,27,99)
+ using ptr_type = Exiv2::BasicIo::UniquePtr;
+#else
+ using ptr_type = Exiv2::BasicIo::AutoPtr;
+#endif
+
+ int open() override;
+ int close() override;
+
+ long write(const Exiv2::byte *data, long wcount) override;
+ long write(BasicIo &src) override;
+ int putb(Exiv2::byte data) override;
+
+ Exiv2::DataBuf read(long rcount) override;
+ long read(Exiv2::byte *buf, long rcount) override ;
+ int getb() override;
+
+ // Does not seem necessary for Read-only support
+ void transfer(Exiv2::BasicIo &src) override;
+
+ int seek(seek_offset_t offset, Exiv2::BasicIo::Position position) override;
+
+
+ // MMapping not supported
+ Exiv2::byte *mmap(bool writable) override {
+ g_debug(__PRETTY_FUNCTION__);
+ return nullptr; }
+ int munmap() override { return 0; }
+
+ long tell() const override;
+ // Cannot tell the size from a random stream - also it does not
+ // seem to be necessary for what we are doing
+ size_t size() const override {
+ g_debug(__PRETTY_FUNCTION__);
+ return -1; }
+
+ bool isopen() const override {
+ g_debug(__PRETTY_FUNCTION__);
+ return true; }
+
+ int error() const override {
+ g_debug(__PRETTY_FUNCTION__);
+ return _error == nullptr ? 0 : 1; }
+
+ bool eof() const override {
+ g_debug(__PRETTY_FUNCTION__);
+ return _eof; }
+
+ std::string path() const {
+ g_debug(__PRETTY_FUNCTION__);
+ return "GIO Wrapper"; }
+
+#if EXIV2_TEST_VERSION(0,27,99)
+ Exiv2::BasicIo::UniquePtr temporary() const {
+ g_debug(__PRETTY_FUNCTION__);
+ return Exiv2::BasicIo::UniquePtr(nullptr);
+ }
+#else
+ Exiv2::BasicIo::AutoPtr temporary() const {
+ g_debug(__PRETTY_FUNCTION__);
+ return Exiv2::BasicIo::AutoPtr(nullptr);
+ }
+#endif
+
+
+private:
+ GIOStream *_is;
+ GSeekable *_seekable;
+ GError *_error;
+ bool _eof;
+}; // class GioIo
+
+} // namespace Internal
+} // namespace GExiv2
+
+#endif // GEXIV2_METADATA_GIO
diff --git a/gexiv2/gexiv2-metadata.cpp b/gexiv2/gexiv2-metadata.cpp
index c520ede..60bd870 100644
--- a/gexiv2/gexiv2-metadata.cpp
+++ b/gexiv2/gexiv2-metadata.cpp
@@ -10,6 +10,7 @@
#include "gexiv2-metadata.h"
#include "gexiv2-metadata-private.h"
+#include "gexiv2-metadata-gio.h"
#include "gexiv2-stream-io.h"
#include "gexiv2-managed-stream.h"
#include "gexiv2-preview-properties.h"
@@ -31,195 +32,6 @@ 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
-
-#if EXIV2_TEST_VERSION(0,27,99)
- using ptr_type = Exiv2::BasicIo::UniquePtr;
-#else
- using ptr_type = Exiv2::BasicIo::AutoPtr;
-#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;
-
-#if EXIV2_TEST_VERSION(0,27,0)
- throw Exiv2::Error(Exiv2::ErrorCode::kerFailedToReadImageData);
-#else
- throw Exiv2::Error(2);
-#endif
- 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));
@@ -398,7 +210,7 @@ gboolean gexiv2_metadata_from_stream(GExiv2Metadata *self, GInputStream *stream,
g_return_val_if_fail (GEXIV2_IS_METADATA (self), FALSE);
try {
- GioIo::ptr_type gio_ptr{new GioIo (stream)};
+ GExiv2::Internal::GioIo::ptr_type gio_ptr{new GExiv2::Internal::GioIo (stream)};
#if EXIV2_TEST_VERSION(0,27,99)
self->priv->image = Exiv2::ImageFactory::open (std::move(gio_ptr));
#else
@@ -560,6 +372,24 @@ gboolean gexiv2_metadata_save_stream (GExiv2Metadata *self, ManagedStreamCallbac
return FALSE;
}
+gboolean gexiv2_metadata_to_stream(GExiv2Metadata *self, GIOStream *stream, GError **error) {
+ g_return_val_if_fail (GEXIV2_IS_METADATA (self), FALSE);
+
+ try {
+ GExiv2::Internal::GioRwIo::ptr_type stream_ptr{new GExiv2::Internal::GioRwIo{stream}};
+
+#if EXIV2_TEST_VERSION(0,27,99)
+ return gexiv2_metadata_save_internal (self, Exiv2::ImageFactory::open (std::move(stream_ptr)),
error);
+#else
+ return gexiv2_metadata_save_internal (self, Exiv2::ImageFactory::open (stream_ptr), error);
+#endif
+ } catch (Exiv2::Error &e) {
+ g_set_error_literal (error, g_quark_from_string ("GExiv2"), e.code (), e.what ());
+ }
+
+ return FALSE;
+}
+
gboolean gexiv2_metadata_has_tag(GExiv2Metadata *self, const gchar* tag) {
g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
g_return_val_if_fail(tag != NULL, FALSE);
diff --git a/gexiv2/gexiv2-metadata.h b/gexiv2/gexiv2-metadata.h
index 54e0e91..60a6933 100644
--- a/gexiv2/gexiv2-metadata.h
+++ b/gexiv2/gexiv2-metadata.h
@@ -317,6 +317,18 @@ gboolean gexiv2_metadata_save_file (GExiv2Metadata
*self, const gchar *path,
*/
gboolean gexiv2_metadata_save_stream (GExiv2Metadata *self,
ManagedStreamCallbacks* cb, GError **error);
+/**
+ * gexiv2_metadata_to_stream:
+ * @self: An instance of #GExiv2Metadata
+ * @ios: A #GIOStream for writing the meta-data to
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Saves the metadata to the file represented by #ios.
+ *
+ * Returns: Boolean success indicator.
+ */
+gboolean gexiv2_metadata_to_stream (GExiv2Metadata *self, GIOStream
*ios, GError **error);
+
/**
* gexiv2_metadata_has_tag:
* @self: An instance of #GExiv2Metadata
diff --git a/gexiv2/meson.build b/gexiv2/meson.build
index 196b298..0af869f 100644
--- a/gexiv2/meson.build
+++ b/gexiv2/meson.build
@@ -47,6 +47,8 @@ gexiv2 = library('gexiv2',
'gexiv2-log-private.h',
'gexiv2-metadata-private.h',
'gexiv2-stream-io.h',
+ 'gexiv2-metadata-gio.h',
+ 'gexiv2-metadata-gio.cpp',
'gexiv2-preview-properties-private.h',
'gexiv2-preview-image-private.h'] +
gexiv2_headers +
diff --git a/tools/gexiv2-copy.vala b/tools/gexiv2-copy.vala
new file mode 100644
index 0000000..eea9e78
--- /dev/null
+++ b/tools/gexiv2-copy.vala
@@ -0,0 +1,43 @@
+/*
+ * gexiv2-dump.vala
+ *
+ * Author(s)
+ * Jim Nelson <jim yorba org>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+int main(string[] args) {
+ if (args.length != 3 || ("--help" in args) || ("-h" in args)) {
+ usage();
+
+ return 1;
+ }
+
+ var in_file = File.new_for_commandline_arg (args[1]);
+ var out_file = File.new_for_commandline_arg (args[2]);
+
+ var metadata = new GExiv2.Metadata();
+ try {
+ metadata.from_stream (in_file.read());
+ } catch (Error err) {
+ print("Failed to open input file %s: %s\n", args[1], err.message);
+ return 2;
+ }
+
+ print ("Opening destination file for reading");
+ try {
+ var input = out_file.read();
+ var output = out_file.replace(null, false, FileCreateFlags.NONE, null);
+ metadata.to_stream (new SimpleIOStream (input, output));
+ } catch (Error err) {
+ print("Failed write to output file %s: %s\n", args[2], err.message);
+ return 3;
+ }
+
+ return 0;
+}
+
+void usage() {
+ stdout.printf("usage: gexiv2-copy IN-FILE OUT-FILE\n\n");
+}
diff --git a/tools/meson.build b/tools/meson.build
index 4ab697d..f665630 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -4,4 +4,10 @@ if vapi_available
include_directories : include_directories('..'),
dependencies : [gobject, vapi, gio],
link_with : gexiv2)
+
+ executable('gexiv2-copy',
+ 'gexiv2-copy.vala',
+ include_directories : include_directories('..'),
+ dependencies : [gobject, vapi, gio],
+ link_with : gexiv2)
endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]