[gimp] Issue #5863: No namespace info available for XMP prefix.
- From: Jehan <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] Issue #5863: No namespace info available for XMP prefix.
- Date: Mon, 14 Dec 2020 20:06:44 +0000 (UTC)
commit 7ed68556c7d2093772fe27ee507e2bc3583b88f3
Author: Jehan <jehan girinstud io>
Date: Mon Dec 14 21:03:43 2020 +0100
Issue #5863: No namespace info available for XMP prefix.
Adding 2 temporary patches for our builds:
- gexiv2-mr20.patch: to be applied over GExiv2 0.12.1. This patch is
already contributed upstream so it won't be necessary once GExiv2
0.12.2 is released.
- 0001-Issue-5863-do-not-raise-WARNINGs-on-Exiv2-unsupporte.patch: to be
applied over GIMP master branch itself. It depends on GExiv2 0.12.2 so
I cannot push it to master until we bump GExiv2 minimum requirement
(which can only happen when v0.12.2 is out then available in Debian
testing, as per our dependency rules).
For the time being, while waiting for upstream releases, all we can do
is wait and apply these patches on our own dev builds (because this bug
is annoying and was reported to us quite a few times already).
...do-not-raise-WARNINGs-on-Exiv2-unsupporte.patch | 66 ++
build/patches/gexiv2-mr20.patch | 748 +++++++++++++++++++++
2 files changed, 814 insertions(+)
---
diff --git a/build/patches/0001-Issue-5863-do-not-raise-WARNINGs-on-Exiv2-unsupporte.patch
b/build/patches/0001-Issue-5863-do-not-raise-WARNINGs-on-Exiv2-unsupporte.patch
new file mode 100644
index 0000000000..c9075ada86
--- /dev/null
+++ b/build/patches/0001-Issue-5863-do-not-raise-WARNINGs-on-Exiv2-unsupporte.patch
@@ -0,0 +1,66 @@
+From d164c9922801631631ba8f275b0b2ce91c71d6df Mon Sep 17 00:00:00 2001
+From: Jehan <jehan girinstud io>
+Date: Sun, 8 Nov 2020 18:54:53 +0100
+Subject: [PATCH] Issue #5863: do not raise WARNINGs on Exiv2 unsupported tags
+ on loading.
+
+WIP. Waiting for GExiv2 to merge a patch I submitted:
+https://gitlab.gnome.org/GNOME/gexiv2/-/merge_requests/20
+
+We will have to bump GExiv2 dependency as well (so master only fix).
+---
+ libgimpbase/gimpmetadata.c | 27 ++++++++++++++++++++++-----
+ 1 file changed, 22 insertions(+), 5 deletions(-)
+
+diff --git a/libgimpbase/gimpmetadata.c b/libgimpbase/gimpmetadata.c
+index 2170d4a4f4..ef312be670 100644
+--- a/libgimpbase/gimpmetadata.c
++++ b/libgimpbase/gimpmetadata.c
+@@ -644,12 +644,20 @@ gimp_metadata_deserialize_text (GMarkupParseContext *context,
+ if (value)
+ {
+ GExiv2Metadata *g2_metadata = GEXIV2_METADATA (parse_data->metadata);
++ GError *error = NULL;
+ gchar **values;
+
+- values = gexiv2_metadata_get_tag_multiple (g2_metadata,
+- parse_data->name);
++ values = gexiv2_metadata_try_get_tag_multiple (g2_metadata,
++ parse_data->name,
++ &error);
+
+- if (values)
++ if (error)
++ {
++ g_printerr ("%s: %s\n", G_STRFUNC, error->message);
++ g_clear_error (&error);
++ g_strfreev (values);
++ }
++ else if (values)
+ {
+ guint length = g_strv_length (values);
+
+@@ -1597,9 +1605,18 @@ gimp_metadata_copy_tag (GExiv2Metadata *src,
+ GExiv2Metadata *dest,
+ const gchar *tag)
+ {
+- gchar **values = gexiv2_metadata_get_tag_multiple (src, tag);
++ gchar **values;
++ GError *error = NULL;
++
++ values = gexiv2_metadata_try_get_tag_multiple (src, tag, &error);
+
+- if (values)
++ if (error)
++ {
++ g_printerr ("%s: %s\n", G_STRFUNC, error->message);
++ g_clear_error (&error);
++ g_strfreev (values);
++ }
++ else if (values)
+ {
+ gexiv2_metadata_set_tag_multiple (dest, tag, (const gchar **) values);
+ g_strfreev (values);
+--
+2.29.2
+
diff --git a/build/patches/gexiv2-mr20.patch b/build/patches/gexiv2-mr20.patch
new file mode 100644
index 0000000000..93a399c5e8
--- /dev/null
+++ b/build/patches/gexiv2-mr20.patch
@@ -0,0 +1,748 @@
+From 45aef278795767012d2f44985f900569df3b8bd3 Mon Sep 17 00:00:00 2001
+From: Jehan <jehan girinstud io>
+Date: Sun, 8 Nov 2020 18:25:34 +0100
+Subject: [PATCH 1/3] Issue #60: alt gexiv2_metadata_try_(g|s)et_tag_multiple()
+ with GError.
+
+Raising GLib warning should not be done on tag errors because calling
+applications may prefer handling these errors differently (and adding a
+log handler for every dependency of a software is not flexible).
+It is much better design to return errors as optional GError.
+---
+ gexiv2/gexiv2-metadata-iptc.cpp | 10 +++--
+ gexiv2/gexiv2-metadata-private.h | 8 ++--
+ gexiv2/gexiv2-metadata-xmp.cpp | 10 +++--
+ gexiv2/gexiv2-metadata.cpp | 73 ++++++++++++++++++++++++--------
+ gexiv2/gexiv2-metadata.h | 34 +++++++++++++++
+ 5 files changed, 105 insertions(+), 30 deletions(-)
+
+diff --git a/gexiv2/gexiv2-metadata-iptc.cpp b/gexiv2/gexiv2-metadata-iptc.cpp
+index 24de73b..efb5824 100644
+--- a/gexiv2/gexiv2-metadata-iptc.cpp
++++ b/gexiv2/gexiv2-metadata-iptc.cpp
+@@ -161,10 +161,11 @@ gboolean gexiv2_metadata_set_iptc_tag_string (GExiv2Metadata *self, const gchar*
+ return FALSE;
+ }
+
+-gchar** gexiv2_metadata_get_iptc_tag_multiple (GExiv2Metadata *self, const gchar* tag) {
++gchar** gexiv2_metadata_get_iptc_tag_multiple (GExiv2Metadata *self, const gchar* tag, GError **error) {
+ g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
+ g_return_val_if_fail(tag != NULL, NULL);
+ g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
++ g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+ Exiv2::IptcData &iptc_data = self->priv->image->iptcData();
+
+@@ -191,7 +192,7 @@ gchar** gexiv2_metadata_get_iptc_tag_multiple (GExiv2Metadata *self, const gchar
+
+ return values;
+ } catch (Exiv2::Error& e) {
+- LOG_ERROR(e);
++ g_set_error_literal (error, g_quark_from_string ("GExiv2"), e.code (), e.what ());
+ }
+
+ g_slist_free_full (list, g_free);
+@@ -200,11 +201,12 @@ gchar** gexiv2_metadata_get_iptc_tag_multiple (GExiv2Metadata *self, const gchar
+ }
+
+ gboolean gexiv2_metadata_set_iptc_tag_multiple (GExiv2Metadata *self, const gchar* tag,
+- const gchar** values) {
++ const gchar** values, GError **error) {
+ g_return_val_if_fail (GEXIV2_IS_METADATA (self), FALSE);
+ g_return_val_if_fail(tag != NULL, FALSE);
+ g_return_val_if_fail(values != NULL, FALSE);
+ g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
++ g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+ Exiv2::IptcData& iptc_data = self->priv->image->iptcData();
+
+@@ -232,7 +234,7 @@ gboolean gexiv2_metadata_set_iptc_tag_multiple (GExiv2Metadata *self, const gcha
+
+ return TRUE;
+ } catch (Exiv2::Error& e) {
+- LOG_ERROR(e);
++ g_set_error_literal (error, g_quark_from_string ("GExiv2"), e.code (), e.what ());
+ }
+
+ return FALSE;
+diff --git a/gexiv2/gexiv2-metadata-private.h b/gexiv2/gexiv2-metadata-private.h
+index d31fa99..989af0b 100644
+--- a/gexiv2/gexiv2-metadata-private.h
++++ b/gexiv2/gexiv2-metadata-private.h
+@@ -62,8 +62,8 @@ G_GNUC_INTERNAL gboolean gexiv2_metadata_set_xmp_tag_string
(GExiv2Metadata *se
+ G_GNUC_INTERNAL gchar* gexiv2_metadata_get_xmp_tag_interpreted_string
(GExiv2Metadata *self, const gchar* tag);
+ G_GNUC_INTERNAL glong gexiv2_metadata_get_xmp_tag_long (GExiv2Metadata *self, const
gchar* tag);
+ G_GNUC_INTERNAL gboolean gexiv2_metadata_set_xmp_tag_long (GExiv2Metadata *self, const
gchar* tag, glong value);
+-G_GNUC_INTERNAL gchar** gexiv2_metadata_get_xmp_tag_multiple (GExiv2Metadata *self,
const gchar* tag);
+-G_GNUC_INTERNAL gboolean gexiv2_metadata_set_xmp_tag_multiple (GExiv2Metadata *self, const
gchar* tag, const gchar** values);
++G_GNUC_INTERNAL gchar** gexiv2_metadata_get_xmp_tag_multiple (GExiv2Metadata *self,
const gchar* tag, GError **error);
++G_GNUC_INTERNAL gboolean gexiv2_metadata_set_xmp_tag_multiple (GExiv2Metadata *self, const
gchar* tag, const gchar** values, GError **error);
+
+ G_GNUC_INTERNAL const gchar* gexiv2_metadata_get_xmp_tag_label (const gchar* tag);
+ G_GNUC_INTERNAL const gchar* gexiv2_metadata_get_xmp_tag_description (const gchar* tag);
+@@ -78,8 +78,8 @@ G_GNUC_INTERNAL gboolean gexiv2_metadata_has_iptc_tag
(GExiv2Metadata *self, c
+ G_GNUC_INTERNAL gchar* gexiv2_metadata_get_iptc_tag_string (GExiv2Metadata
*self, const gchar* tag);
+ G_GNUC_INTERNAL gboolean gexiv2_metadata_set_iptc_tag_string (GExiv2Metadata *self, const
gchar* tag, const gchar* value);
+ G_GNUC_INTERNAL gchar* gexiv2_metadata_get_iptc_tag_interpreted_string
(GExiv2Metadata *self, const gchar* tag);
+-G_GNUC_INTERNAL gchar** gexiv2_metadata_get_iptc_tag_multiple (GExiv2Metadata
*self, const gchar* tag);
+-G_GNUC_INTERNAL gboolean gexiv2_metadata_set_iptc_tag_multiple (GExiv2Metadata *self, const
gchar* tag, const gchar** values);
++G_GNUC_INTERNAL gchar** gexiv2_metadata_get_iptc_tag_multiple (GExiv2Metadata
*self, const gchar* tag, GError **error);
++G_GNUC_INTERNAL gboolean gexiv2_metadata_set_iptc_tag_multiple (GExiv2Metadata *self, const
gchar* tag, const gchar** values, GError **error);
+
+ G_GNUC_INTERNAL const gchar* gexiv2_metadata_get_iptc_tag_label (const gchar* tag);
+ G_GNUC_INTERNAL const gchar* gexiv2_metadata_get_iptc_tag_description (const gchar* tag);
+diff --git a/gexiv2/gexiv2-metadata-xmp.cpp b/gexiv2/gexiv2-metadata-xmp.cpp
+index 784ad86..4647d36 100644
+--- a/gexiv2/gexiv2-metadata-xmp.cpp
++++ b/gexiv2/gexiv2-metadata-xmp.cpp
+@@ -269,10 +269,11 @@ gboolean gexiv2_metadata_set_xmp_tag_long (GExiv2Metadata *self, const gchar* ta
+ return FALSE;
+ }
+
+-gchar** gexiv2_metadata_get_xmp_tag_multiple (GExiv2Metadata *self, const gchar* tag) {
++gchar** gexiv2_metadata_get_xmp_tag_multiple (GExiv2Metadata *self, const gchar* tag, GError **error) {
+ g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
+ g_return_val_if_fail(tag != NULL, NULL);
+ g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
++ g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+ Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+
+@@ -294,7 +295,7 @@ gchar** gexiv2_metadata_get_xmp_tag_multiple (GExiv2Metadata *self, const gchar*
+ return array;
+ }
+ } catch (Exiv2::Error& e) {
+- LOG_ERROR(e);
++ g_set_error_literal (error, g_quark_from_string ("GExiv2"), e.code (), e.what ());
+ }
+
+ gchar **array = g_new (gchar*, 1);
+@@ -304,11 +305,12 @@ gchar** gexiv2_metadata_get_xmp_tag_multiple (GExiv2Metadata *self, const gchar*
+ }
+
+ gboolean gexiv2_metadata_set_xmp_tag_multiple (GExiv2Metadata *self, const gchar* tag,
+- const gchar** values) {
++ const gchar** values, GError **error) {
+ g_return_val_if_fail(GEXIV2_IS_METADATA (self), FALSE);
+ g_return_val_if_fail(tag != NULL, FALSE);
+ g_return_val_if_fail(values != NULL, FALSE);
+ g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
++ g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+ Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+
+@@ -330,7 +332,7 @@ gboolean gexiv2_metadata_set_xmp_tag_multiple (GExiv2Metadata *self, const gchar
+
+ return TRUE;
+ } catch (Exiv2::Error& e) {
+- LOG_ERROR(e);
++ g_set_error_literal (error, g_quark_from_string ("GExiv2"), e.code (), e.what ());
+ }
+
+ return FALSE;
+diff --git a/gexiv2/gexiv2-metadata.cpp b/gexiv2/gexiv2-metadata.cpp
+index 5a2a2bb..3b04017 100644
+--- a/gexiv2/gexiv2-metadata.cpp
++++ b/gexiv2/gexiv2-metadata.cpp
+@@ -945,35 +945,72 @@ gchar* gexiv2_metadata_get_tag_interpreted_string (GExiv2Metadata *self, const g
+ return NULL;
+ }
+
+-gchar** gexiv2_metadata_get_tag_multiple(GExiv2Metadata *self, const gchar* tag) {
+- g_return_val_if_fail(GEXIV2_IS_METADATA(self), NULL);
+- g_return_val_if_fail(tag != NULL, NULL);
+- g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
+-
++gchar** gexiv2_metadata_try_get_tag_multiple(GExiv2Metadata *self, const gchar* tag, GError **error) {
++ g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
++ g_return_val_if_fail(tag != nullptr, nullptr);
++ g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
++
+ if (gexiv2_metadata_is_xmp_tag(tag))
+- return gexiv2_metadata_get_xmp_tag_multiple(self, tag);
+-
++ return gexiv2_metadata_get_xmp_tag_multiple(self, tag, error);
++
+ if (gexiv2_metadata_is_iptc_tag(tag))
+- return gexiv2_metadata_get_iptc_tag_multiple(self, tag);
+-
++ return gexiv2_metadata_get_iptc_tag_multiple(self, tag, error);
++
+ return NULL;
+ }
+
+-gboolean gexiv2_metadata_set_tag_multiple(GExiv2Metadata *self, const gchar* tag, const gchar** values) {
++gboolean gexiv2_metadata_try_set_tag_multiple(GExiv2Metadata *self, const gchar* tag, const gchar** values,
GError **error) {
+ g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
+- g_return_val_if_fail(tag != NULL, FALSE);
+- g_return_val_if_fail(values != NULL, FALSE);
+- g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
+-
++ g_return_val_if_fail(tag != nullptr, FALSE);
++ g_return_val_if_fail(values != nullptr, FALSE);
++ g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
++
+ if (gexiv2_metadata_is_xmp_tag(tag))
+- return gexiv2_metadata_set_xmp_tag_multiple(self, tag, values);
+-
++ return gexiv2_metadata_set_xmp_tag_multiple(self, tag, values, error);
++
+ if (gexiv2_metadata_is_iptc_tag(tag))
+- return gexiv2_metadata_set_iptc_tag_multiple(self, tag, values);
+-
++ return gexiv2_metadata_set_iptc_tag_multiple(self, tag, values, error);
++
+ return FALSE;
+ }
+
++gchar** gexiv2_metadata_get_tag_multiple(GExiv2Metadata *self, const gchar* tag) {
++ gchar **tags = nullptr;
++ GError *error = nullptr;
++
++ g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
++ g_return_val_if_fail(tag != nullptr, nullptr);
++ g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
++
++ tags = gexiv2_metadata_try_get_tag_multiple(self, tag, &error);
++
++ if (error) {
++ g_warning("%s", error->message);
++ g_clear_error(&error);
++ }
++
++ return tags;
++}
++
++gboolean gexiv2_metadata_set_tag_multiple(GExiv2Metadata *self, const gchar* tag, const gchar** values) {
++ GError *error = nullptr;
++ gboolean success = FALSE;
++
++ g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
++ g_return_val_if_fail(tag != nullptr, FALSE);
++ g_return_val_if_fail(values != nullptr, FALSE);
++ g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
++
++ success = gexiv2_metadata_try_set_tag_multiple(self, tag, values, &error);
++
++ if (error) {
++ g_warning("%s", error->message);
++ g_clear_error(&error);
++ }
++
++ return success;
++}
++
+ glong gexiv2_metadata_get_tag_long(GExiv2Metadata *self, const gchar* tag) {
+ g_return_val_if_fail(GEXIV2_IS_METADATA(self), 0);
+ g_return_val_if_fail(tag != NULL, 0);
+diff --git a/gexiv2/gexiv2-metadata.h b/gexiv2/gexiv2-metadata.h
+index f65db7e..89e1495 100644
+--- a/gexiv2/gexiv2-metadata.h
++++ b/gexiv2/gexiv2-metadata.h
+@@ -562,6 +562,32 @@ glong gexiv2_metadata_get_tag_long (GExiv2Metadata
*self, const gchar* tag);
+ gboolean gexiv2_metadata_set_tag_long (GExiv2Metadata *self, const gchar* tag,
glong value);
+
+
++/**
++ * gexiv2_metadata_try_get_tag_multiple:
++ * @self: An instance of #GExiv2Metadata
++ * @tag: Exiv2 tag name
++ * @error: (allow-none): A return location for a #GError or %nullptr
++ *
++ * The Exiv2 Tag Reference can be found at <ulink url="http://exiv2.org/metadata.html"></ulink>
++ *
++ * Returns: (transfer full) (allow-none) (array zero-terminated=1): The multiple string values of
++ * the tag
++ */
++gchar** gexiv2_metadata_try_get_tag_multiple (GExiv2Metadata *self, const gchar*
tag, GError **error);
++
++/**
++ * gexiv2_metadata_try_set_tag_multiple:
++ * @self: An instance of #GExiv2Metadata
++ * @tag: Exiv2 tag name
++ * @values: (array zero-terminated=1): An array of values to set or replace the existing value(s)
++ * @error: (allow-none): A return location for a #GError or %nullptr
++ *
++ * The Exiv2 Tag Reference can be found at <ulink url="http://exiv2.org/metadata.html"></ulink>
++ *
++ * Returns: Boolean success value
++ */
++gboolean gexiv2_metadata_try_set_tag_multiple (GExiv2Metadata *self, const gchar* tag,
const gchar** values, GError **error);
++
+ /**
+ * gexiv2_metadata_get_tag_multiple:
+ * @self: An instance of #GExiv2Metadata
+@@ -569,6 +595,10 @@ gboolean gexiv2_metadata_set_tag_long (GExiv2Metadata *self, const
gchar* tag,
+ *
+ * The Exiv2 Tag Reference can be found at <ulink url="http://exiv2.org/metadata.html"></ulink>
+ *
++ * In case of error, a GLib warning will be logged. Use instead
++ * gexiv2_metadata_try_get_tag_multiple() if you want to avoid this and
++ * control if and how the error is outputted.
++ *
+ * Returns: (transfer full) (allow-none) (array zero-terminated=1): The multiple string values of
+ * the tag
+ */
+@@ -582,6 +612,10 @@ gchar** gexiv2_metadata_get_tag_multiple (GExiv2Metadata
*self, const gchar* t
+ *
+ * The Exiv2 Tag Reference can be found at <ulink url="http://exiv2.org/metadata.html"></ulink>
+ *
++ * In case of error, a GLib warning will be logged. Use instead
++ * gexiv2_metadata_try_set_tag_multiple() if you want to avoid this and
++ * control if and how the error is outputted.
++ *
+ * Returns: Boolean success value
+ */
+ gboolean gexiv2_metadata_set_tag_multiple (GExiv2Metadata *self, const gchar* tag,
const gchar** values);
+--
+GitLab
+
+
+From 52c3a2b1442b52d95abd561a5973862c46f740ea Mon Sep 17 00:00:00 2001
+From: Jehan <jehan girinstud io>
+Date: Sun, 8 Nov 2020 19:22:54 +0100
+Subject: [PATCH 2/3] New gexiv2_metadata_try_(g|s)et_tag_string() variants
+ with GError.
+
+Similarly to my previous commit, gexiv2_metadata_set_tag_string() and
+gexiv2_metadata_get_tag_string() should have variants which just set a
+GError appropriately on tag error, rather than raising a WARNING.
+---
+ gexiv2/gexiv2-metadata-exif.cpp | 10 +++---
+ gexiv2/gexiv2-metadata-gps.cpp | 6 ++--
+ gexiv2/gexiv2-metadata-iptc.cpp | 10 +++---
+ gexiv2/gexiv2-metadata-private.h | 12 +++----
+ gexiv2/gexiv2-metadata-xmp.cpp | 10 +++---
+ gexiv2/gexiv2-metadata.cpp | 62 +++++++++++++++++++++++++-------
+ gexiv2/gexiv2-metadata.h | 33 +++++++++++++++++
+ 7 files changed, 109 insertions(+), 34 deletions(-)
+
+diff --git a/gexiv2/gexiv2-metadata-exif.cpp b/gexiv2/gexiv2-metadata-exif.cpp
+index 15cf116..81e54b3 100644
+--- a/gexiv2/gexiv2-metadata-exif.cpp
++++ b/gexiv2/gexiv2-metadata-exif.cpp
+@@ -97,10 +97,11 @@ gchar** gexiv2_metadata_get_exif_tags (GExiv2Metadata *self) {
+ return data;
+ }
+
+-gchar* gexiv2_metadata_get_exif_tag_string (GExiv2Metadata *self, const gchar* tag) {
++gchar* gexiv2_metadata_get_exif_tag_string (GExiv2Metadata *self, const gchar* tag, GError **error) {
+ g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
+ g_return_val_if_fail(tag != NULL, NULL);
+ g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
++ g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+ Exiv2::ExifData &exif_data = self->priv->image->exifData();
+
+@@ -112,7 +113,7 @@ gchar* gexiv2_metadata_get_exif_tag_string (GExiv2Metadata *self, const gchar* t
+ if (it != exif_data.end())
+ return g_strdup (it->toString ().c_str ());
+ } catch (Exiv2::Error& e) {
+- LOG_ERROR(e);
++ g_set_error_literal (error, g_quark_from_string ("GExiv2"), e.code (), e.what ());
+ }
+
+ return NULL;
+@@ -143,18 +144,19 @@ gchar* gexiv2_metadata_get_exif_tag_interpreted_string (GExiv2Metadata *self, co
+ return NULL;
+ }
+
+-gboolean gexiv2_metadata_set_exif_tag_string (GExiv2Metadata *self, const gchar* tag, const gchar* value) {
++gboolean gexiv2_metadata_set_exif_tag_string (GExiv2Metadata *self, const gchar* tag, const gchar* value,
GError **error) {
+ g_return_val_if_fail(GEXIV2_IS_METADATA (self), FALSE);
+ g_return_val_if_fail(tag != NULL, FALSE);
+ g_return_val_if_fail(value != NULL, FALSE);
+ g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
++ g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+ try {
+ self->priv->image->exifData()[tag] = value;
+
+ return TRUE;
+ } catch (Exiv2::Error& e) {
+- LOG_ERROR(e);
++ g_set_error_literal (error, g_quark_from_string ("GExiv2"), e.code (), e.what ());
+ }
+
+ return FALSE;
+diff --git a/gexiv2/gexiv2-metadata-gps.cpp b/gexiv2/gexiv2-metadata-gps.cpp
+index deeb4ac..7d0d18a 100644
+--- a/gexiv2/gexiv2-metadata-gps.cpp
++++ b/gexiv2/gexiv2-metadata-gps.cpp
+@@ -56,7 +56,7 @@ gboolean gexiv2_metadata_get_gps_longitude (GExiv2Metadata *self, gdouble *longi
+ double min, sec;
+ *longitude = 0.0;
+
+- gchar* longitude_ref = gexiv2_metadata_get_exif_tag_string (self, "Exif.GPSInfo.GPSLongitudeRef");
++ gchar* longitude_ref = gexiv2_metadata_get_exif_tag_string (self, "Exif.GPSInfo.GPSLongitudeRef",
nullptr);
+ GPointer longitude_ref_guard(longitude_ref);
+
+ if (longitude_ref == NULL || longitude_ref[0] == '\0') {
+@@ -105,7 +105,7 @@ gboolean gexiv2_metadata_get_gps_latitude (GExiv2Metadata *self, gdouble *latitu
+ double min, sec;
+ *latitude = 0.0;
+
+- gchar* latitude_ref = gexiv2_metadata_get_exif_tag_string (self, "Exif.GPSInfo.GPSLatitudeRef");
++ gchar* latitude_ref = gexiv2_metadata_get_exif_tag_string (self, "Exif.GPSInfo.GPSLatitudeRef",
nullptr);
+ GPointer latitude_ref_guard(latitude_ref);
+
+ if (latitude_ref == NULL || latitude_ref[0] == '\0') {
+@@ -153,7 +153,7 @@ gboolean gexiv2_metadata_get_gps_altitude (GExiv2Metadata *self, gdouble *altitu
+ try {
+ *altitude = 0.0;
+
+- gchar* altitude_ref = gexiv2_metadata_get_exif_tag_string (self, "Exif.GPSInfo.GPSAltitudeRef");
++ gchar* altitude_ref = gexiv2_metadata_get_exif_tag_string (self, "Exif.GPSInfo.GPSAltitudeRef",
nullptr);
+ GPointer altitude_ref_guard(altitude_ref);
+
+ if (altitude_ref == NULL || altitude_ref[0] == '\0') {
+diff --git a/gexiv2/gexiv2-metadata-iptc.cpp b/gexiv2/gexiv2-metadata-iptc.cpp
+index efb5824..8340d72 100644
+--- a/gexiv2/gexiv2-metadata-iptc.cpp
++++ b/gexiv2/gexiv2-metadata-iptc.cpp
+@@ -97,10 +97,11 @@ gchar** gexiv2_metadata_get_iptc_tags (GExiv2Metadata *self) {
+ return data;
+ }
+
+-gchar* gexiv2_metadata_get_iptc_tag_string (GExiv2Metadata *self, const gchar* tag) {
++gchar* gexiv2_metadata_get_iptc_tag_string (GExiv2Metadata *self, const gchar* tag, GError **error) {
+ g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
+ g_return_val_if_fail(tag != NULL, NULL);
+ g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
++ g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+ Exiv2::IptcData& iptc_data = self->priv->image->iptcData();
+
+@@ -112,7 +113,7 @@ gchar* gexiv2_metadata_get_iptc_tag_string (GExiv2Metadata *self, const gchar* t
+ if (it != iptc_data.end())
+ return g_strdup (it->toString ().c_str ());
+ } catch (Exiv2::Error& e) {
+- LOG_ERROR(e);
++ g_set_error_literal (error, g_quark_from_string ("GExiv2"), e.code (), e.what ());
+ }
+
+ return NULL;
+@@ -144,18 +145,19 @@ gchar* gexiv2_metadata_get_iptc_tag_interpreted_string (GExiv2Metadata *self, co
+ }
+
+ gboolean gexiv2_metadata_set_iptc_tag_string (GExiv2Metadata *self, const gchar* tag,
+- const gchar* value) {
++ const gchar* value, GError **error) {
+ g_return_val_if_fail (GEXIV2_IS_METADATA (self), FALSE);
+ g_return_val_if_fail(tag != NULL, FALSE);
+ g_return_val_if_fail(value != NULL, FALSE);
+ g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
++ g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+ try {
+ self->priv->image->iptcData()[tag] = value;
+
+ return TRUE;
+ } catch (Exiv2::Error& e) {
+- LOG_ERROR(e);
++ g_set_error_literal (error, g_quark_from_string ("GExiv2"), e.code (), e.what ());
+ }
+
+ return FALSE;
+diff --git a/gexiv2/gexiv2-metadata-private.h b/gexiv2/gexiv2-metadata-private.h
+index 989af0b..30e3c13 100644
+--- a/gexiv2/gexiv2-metadata-private.h
++++ b/gexiv2/gexiv2-metadata-private.h
+@@ -42,8 +42,8 @@ struct _GExiv2MetadataPrivate
+
+ G_GNUC_INTERNAL gboolean gexiv2_metadata_has_exif_tag (GExiv2Metadata *self, const
gchar* tag);
+ G_GNUC_INTERNAL gboolean gexiv2_metadata_clear_exif_tag (GExiv2Metadata *self, const
gchar* tag);
+-G_GNUC_INTERNAL gchar* gexiv2_metadata_get_exif_tag_string (GExiv2Metadata
*self, const gchar* tag);
+-G_GNUC_INTERNAL gboolean gexiv2_metadata_set_exif_tag_string (GExiv2Metadata *self, const
gchar* tag, const gchar* value);
++G_GNUC_INTERNAL gchar* gexiv2_metadata_get_exif_tag_string (GExiv2Metadata
*self, const gchar* tag, GError **error);
++G_GNUC_INTERNAL gboolean gexiv2_metadata_set_exif_tag_string (GExiv2Metadata *self, const
gchar* tag, const gchar* value, GError **error);
+ G_GNUC_INTERNAL gchar* gexiv2_metadata_get_exif_tag_interpreted_string
(GExiv2Metadata *self, const gchar* tag);
+ G_GNUC_INTERNAL glong gexiv2_metadata_get_exif_tag_long (GExiv2Metadata *self, const
gchar* tag);
+ G_GNUC_INTERNAL gboolean gexiv2_metadata_set_exif_tag_long (GExiv2Metadata *self, const
gchar* tag, glong value);
+@@ -57,8 +57,8 @@ G_GNUC_INTERNAL GBytes* gexiv2_metadata_get_exif_tag_raw
(GExiv2Metadata *self
+
+ G_GNUC_INTERNAL gboolean gexiv2_metadata_clear_xmp_tag (GExiv2Metadata *self, const
gchar* tag);
+ G_GNUC_INTERNAL gboolean gexiv2_metadata_has_xmp_tag (GExiv2Metadata
*self, const gchar* tag);
+-G_GNUC_INTERNAL gchar* gexiv2_metadata_get_xmp_tag_string (GExiv2Metadata
*self, const gchar* tag);
+-G_GNUC_INTERNAL gboolean gexiv2_metadata_set_xmp_tag_string (GExiv2Metadata *self, const
gchar* tag, const gchar* value);
++G_GNUC_INTERNAL gchar* gexiv2_metadata_get_xmp_tag_string (GExiv2Metadata
*self, const gchar* tag, GError **error);
++G_GNUC_INTERNAL gboolean gexiv2_metadata_set_xmp_tag_string (GExiv2Metadata *self, const
gchar* tag, const gchar* value, GError **error);
+ G_GNUC_INTERNAL gchar* gexiv2_metadata_get_xmp_tag_interpreted_string
(GExiv2Metadata *self, const gchar* tag);
+ G_GNUC_INTERNAL glong gexiv2_metadata_get_xmp_tag_long (GExiv2Metadata *self, const
gchar* tag);
+ G_GNUC_INTERNAL gboolean gexiv2_metadata_set_xmp_tag_long (GExiv2Metadata *self, const
gchar* tag, glong value);
+@@ -75,8 +75,8 @@ G_GNUC_INTERNAL GBytes* gexiv2_metadata_get_xmp_tag_raw
(GExiv2Metadata *self
+
+ G_GNUC_INTERNAL gboolean gexiv2_metadata_clear_iptc_tag (GExiv2Metadata *self, const
gchar* tag);
+ G_GNUC_INTERNAL gboolean gexiv2_metadata_has_iptc_tag (GExiv2Metadata *self, const
gchar* tag);
+-G_GNUC_INTERNAL gchar* gexiv2_metadata_get_iptc_tag_string (GExiv2Metadata
*self, const gchar* tag);
+-G_GNUC_INTERNAL gboolean gexiv2_metadata_set_iptc_tag_string (GExiv2Metadata *self, const
gchar* tag, const gchar* value);
++G_GNUC_INTERNAL gchar* gexiv2_metadata_get_iptc_tag_string (GExiv2Metadata
*self, const gchar* tag, GError **error);
++G_GNUC_INTERNAL gboolean gexiv2_metadata_set_iptc_tag_string (GExiv2Metadata *self, const
gchar* tag, const gchar* value, GError **error);
+ G_GNUC_INTERNAL gchar* gexiv2_metadata_get_iptc_tag_interpreted_string
(GExiv2Metadata *self, const gchar* tag);
+ G_GNUC_INTERNAL gchar** gexiv2_metadata_get_iptc_tag_multiple (GExiv2Metadata
*self, const gchar* tag, GError **error);
+ G_GNUC_INTERNAL gboolean gexiv2_metadata_set_iptc_tag_multiple (GExiv2Metadata *self, const
gchar* tag, const gchar** values, GError **error);
+diff --git a/gexiv2/gexiv2-metadata-xmp.cpp b/gexiv2/gexiv2-metadata-xmp.cpp
+index 4647d36..87795a4 100644
+--- a/gexiv2/gexiv2-metadata-xmp.cpp
++++ b/gexiv2/gexiv2-metadata-xmp.cpp
+@@ -126,10 +126,11 @@ gchar** gexiv2_metadata_get_xmp_tags (GExiv2Metadata *self) {
+ return data;
+ }
+
+-gchar* gexiv2_metadata_get_xmp_tag_string (GExiv2Metadata *self, const gchar* tag) {
++gchar* gexiv2_metadata_get_xmp_tag_string (GExiv2Metadata *self, const gchar* tag, GError **error) {
+ g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
+ g_return_val_if_fail(tag != NULL, NULL);
+ g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
++ g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+ Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+
+@@ -141,7 +142,7 @@ gchar* gexiv2_metadata_get_xmp_tag_string (GExiv2Metadata *self, const gchar* ta
+ if (it != xmp_data.end())
+ return g_strdup (it->toString ().c_str ());
+ } catch (Exiv2::Error& e) {
+- LOG_ERROR(e);
++ g_set_error_literal (error, g_quark_from_string ("GExiv2"), e.code (), e.what ());
+ }
+
+ return NULL;
+@@ -215,18 +216,19 @@ gboolean gexiv2_metadata_set_xmp_tag_struct (GExiv2Metadata *self, const gchar*
+ }
+
+ gboolean gexiv2_metadata_set_xmp_tag_string (GExiv2Metadata *self, const gchar* tag,
+- const gchar* value) {
++ const gchar* value, GError **error) {
+ g_return_val_if_fail(GEXIV2_IS_METADATA (self), FALSE);
+ g_return_val_if_fail(tag != NULL, FALSE);
+ g_return_val_if_fail(value != NULL, FALSE);
+ g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
++ g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+ try {
+ self->priv->image->xmpData()[tag] = value;
+
+ return TRUE;
+ } catch (Exiv2::Error& e) {
+- LOG_ERROR(e);
++ g_set_error_literal (error, g_quark_from_string ("GExiv2"), e.code (), e.what ());
+ }
+
+ return FALSE;
+diff --git a/gexiv2/gexiv2-metadata.cpp b/gexiv2/gexiv2-metadata.cpp
+index 3b04017..426a55d 100644
+--- a/gexiv2/gexiv2-metadata.cpp
++++ b/gexiv2/gexiv2-metadata.cpp
+@@ -894,40 +894,76 @@ gboolean gexiv2_metadata_is_iptc_tag(const gchar* tag) {
+ return g_ascii_strncasecmp("Iptc.", tag, 5) == 0;
+ }
+
+-gchar* gexiv2_metadata_get_tag_string (GExiv2Metadata *self, const gchar* tag) {
+- g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
+- g_return_val_if_fail(tag != NULL, NULL);
+- g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
++gchar* gexiv2_metadata_try_get_tag_string (GExiv2Metadata *self, const gchar* tag, GError **error) {
++ g_return_val_if_fail(GEXIV2_IS_METADATA (self), nullptr);
++ g_return_val_if_fail(tag != nullptr, nullptr);
++ g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+
+ if (gexiv2_metadata_is_xmp_tag(tag))
+- return gexiv2_metadata_get_xmp_tag_string (self, tag);
++ return gexiv2_metadata_get_xmp_tag_string (self, tag, error);
+
+ if (gexiv2_metadata_is_exif_tag(tag))
+- return gexiv2_metadata_get_exif_tag_string (self, tag);
++ return gexiv2_metadata_get_exif_tag_string (self, tag, error);
+
+ if (gexiv2_metadata_is_iptc_tag(tag))
+- return gexiv2_metadata_get_iptc_tag_string (self, tag);
++ return gexiv2_metadata_get_iptc_tag_string (self, tag, error);
+
+ return NULL;
+ }
+
+-gboolean gexiv2_metadata_set_tag_string (GExiv2Metadata *self, const gchar* tag, const gchar* value) {
++gboolean gexiv2_metadata_try_set_tag_string (GExiv2Metadata *self, const gchar* tag, const gchar* value,
GError **error) {
+ g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
+- g_return_val_if_fail(tag != NULL, FALSE);
+- g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
++ g_return_val_if_fail(tag != nullptr, FALSE);
++ g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
+ if (gexiv2_metadata_is_xmp_tag(tag))
+- return gexiv2_metadata_set_xmp_tag_string(self, tag, value);
++ return gexiv2_metadata_set_xmp_tag_string(self, tag, value, error);
+
+ if (gexiv2_metadata_is_exif_tag(tag))
+- return gexiv2_metadata_set_exif_tag_string(self, tag, value);
++ return gexiv2_metadata_set_exif_tag_string(self, tag, value, error);
+
+ if (gexiv2_metadata_is_iptc_tag(tag))
+- return gexiv2_metadata_set_iptc_tag_string(self, tag, value);
++ return gexiv2_metadata_set_iptc_tag_string(self, tag, value, error);
+
+ return FALSE;
+ }
+
++gchar* gexiv2_metadata_get_tag_string (GExiv2Metadata *self, const gchar* tag) {
++ gchar *value;
++ GError *error = nullptr;
++
++ g_return_val_if_fail(GEXIV2_IS_METADATA (self), nullptr);
++ g_return_val_if_fail(tag != nullptr, nullptr);
++ g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
++
++ value = gexiv2_metadata_try_get_tag_string (self, tag, &error);
++
++ if (error) {
++ g_warning("%s", error->message);
++ g_clear_error(&error);
++ }
++
++ return value;
++}
++
++gboolean gexiv2_metadata_set_tag_string (GExiv2Metadata *self, const gchar* tag, const gchar* value) {
++ gboolean success;
++ GError *error = nullptr;
++
++ g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
++ g_return_val_if_fail(tag != nullptr, FALSE);
++ g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
++
++ success = gexiv2_metadata_try_set_tag_string(self, tag, value, &error);
++
++ if (error) {
++ g_warning("%s", error->message);
++ g_clear_error(&error);
++ }
++
++ return success;
++}
++
+ gchar* gexiv2_metadata_get_tag_interpreted_string (GExiv2Metadata *self, const gchar* tag) {
+ g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
+ g_return_val_if_fail(tag != NULL, NULL);
+diff --git a/gexiv2/gexiv2-metadata.h b/gexiv2/gexiv2-metadata.h
+index 89e1495..3315d92 100644
+--- a/gexiv2/gexiv2-metadata.h
++++ b/gexiv2/gexiv2-metadata.h
+@@ -489,6 +489,31 @@ gint gexiv2_metadata_get_pixel_width (GExiv2Metadata
*self);
+ */
+ gint gexiv2_metadata_get_pixel_height (GExiv2Metadata *self);
+
++/**
++ * gexiv2_metadata_try_get_tag_string:
++ * @self: An instance of #GExiv2Metadata
++ * @tag: Exiv2 tag name
++ * @error: (allow-none): A return location for a #GError or %nullptr
++ *
++ * The Exiv2 Tag Reference can be found at <ulink url="http://exiv2.org/metadata.html"></ulink>
++ *
++ * Returns: (transfer full) (allow-none): The tag's value as a string
++ */
++gchar* gexiv2_metadata_try_get_tag_string (GExiv2Metadata *self, const gchar*
tag, GError **error);
++
++/**
++ * gexiv2_metadata_try_set_tag_string:
++ * @self: An instance of #GExiv2Metadata
++ * @tag: Exiv2 tag name
++ * @value: The value to set or replace the existing value
++ * @error: (allow-none): A return location for a #GError or %nullptr
++ *
++ * The Exiv2 Tag Reference can be found at <ulink url="http://exiv2.org/metadata.html"></ulink>
++ *
++ * Returns: TRUE on success
++ */
++gboolean gexiv2_metadata_try_set_tag_string (GExiv2Metadata *self, const gchar* tag,
const gchar* value, GError **error);
++
+ /**
+ * gexiv2_metadata_get_tag_string:
+ * @self: An instance of #GExiv2Metadata
+@@ -496,6 +521,10 @@ gint gexiv2_metadata_get_pixel_height (GExiv2Metadata
*self);
+ *
+ * The Exiv2 Tag Reference can be found at <ulink url="http://exiv2.org/metadata.html"></ulink>
+ *
++ * In case of error, a GLib warning will be logged. Use instead
++ * gexiv2_metadata_try_get_tag_string() if you want to avoid this and
++ * control if and how the error is outputted.
++ *
+ * Returns: (transfer full) (allow-none): The tag's value as a string
+ */
+ gchar* gexiv2_metadata_get_tag_string (GExiv2Metadata *self, const gchar*
tag);
+@@ -508,6 +537,10 @@ gchar* gexiv2_metadata_get_tag_string (GExiv2Metadata
*self, const gchar* tag
+ *
+ * The Exiv2 Tag Reference can be found at <ulink url="http://exiv2.org/metadata.html"></ulink>
+ *
++ * In case of error, a GLib warning will be logged. Use instead
++ * gexiv2_metadata_try_set_tag_string() if you want to avoid this and
++ * control if and how the error is outputted.
++ *
+ * Returns: TRUE on success
+ */
+ gboolean gexiv2_metadata_set_tag_string (GExiv2Metadata *self, const gchar* tag,
const gchar* value);
+--
+GitLab
+
+
+From 5377a0e2912d1a93dcdd38dfff9b1f68223cef53 Mon Sep 17 00:00:00 2001
+From: Jehan <jehan girinstud io>
+Date: Tue, 10 Nov 2020 20:11:06 +0100
+Subject: [PATCH 3/3] gexiv2: properly deprecate functions in favor of
+ gexiv2_metadata_try*().
+
+---
+ gexiv2/gexiv2-metadata.h | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/gexiv2/gexiv2-metadata.h b/gexiv2/gexiv2-metadata.h
+index 3315d92..f51d85f 100644
+--- a/gexiv2/gexiv2-metadata.h
++++ b/gexiv2/gexiv2-metadata.h
+@@ -526,7 +526,10 @@ gboolean gexiv2_metadata_try_set_tag_string (GExiv2Metadata *self, const
gchar*
+ * control if and how the error is outputted.
+ *
+ * Returns: (transfer full) (allow-none): The tag's value as a string
++ *
++ * Deprecated: 0.12.2: Use gexiv2_metadata_try_get_tag_string() instead.
+ */
++G_DEPRECATED_FOR(gexiv2_metadata_try_get_tag_string)
+ gchar* gexiv2_metadata_get_tag_string (GExiv2Metadata *self, const gchar*
tag);
+
+ /**
+@@ -542,7 +545,10 @@ gchar* gexiv2_metadata_get_tag_string (GExiv2Metadata
*self, const gchar* tag
+ * control if and how the error is outputted.
+ *
+ * Returns: TRUE on success
++ *
++ * Deprecated: 0.12.2: Use gexiv2_metadata_try_set_tag_string() instead.
+ */
++G_DEPRECATED_FOR(gexiv2_metadata_try_set_tag_string)
+ gboolean gexiv2_metadata_set_tag_string (GExiv2Metadata *self, const gchar* tag,
const gchar* value);
+
+ /**
+@@ -634,7 +640,10 @@ gboolean gexiv2_metadata_try_set_tag_multiple (GExiv2Metadata *self, const
gcha
+ *
+ * Returns: (transfer full) (allow-none) (array zero-terminated=1): The multiple string values of
+ * the tag
++ *
++ * Deprecated: 0.12.2: Use gexiv2_metadata_try_get_tag_multiple() instead.
+ */
++G_DEPRECATED_FOR(gexiv2_metadata_try_get_tag_multiple)
+ gchar** gexiv2_metadata_get_tag_multiple (GExiv2Metadata *self, const gchar*
tag);
+
+ /**
+@@ -650,7 +659,10 @@ gchar** gexiv2_metadata_get_tag_multiple (GExiv2Metadata
*self, const gchar* t
+ * control if and how the error is outputted.
+ *
+ * Returns: Boolean success value
++ *
++ * Deprecated: 0.12.2: Use gexiv2_metadata_try_set_tag_multiple:() instead.
+ */
++G_DEPRECATED_FOR(gexiv2_metadata_try_set_tag_multiple)
+ gboolean gexiv2_metadata_set_tag_multiple (GExiv2Metadata *self, const gchar* tag,
const gchar** values);
+
+ /**
+--
+GitLab
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]