[gexiv2] Fix gexiv2_metadata_try_get_tag_multiple() xmpText/langAlt return values
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gexiv2] Fix gexiv2_metadata_try_get_tag_multiple() xmpText/langAlt return values
- Date: Mon, 14 Dec 2020 19:31:16 +0000 (UTC)
commit 88d83208e9756a26c6a8e33adeea886b561b5bed
Author: postscript-dev <43813-postscript-dev users noreply gitlab gnome org>
Date: Sat Nov 21 15:38:57 2020 +0000
Fix gexiv2_metadata_try_get_tag_multiple() xmpText/langAlt return values
Function returns incorrect values when tag is of type xmpText or
altLang (see Gexiv2 Issue GNOME/gexiv2#61).
Fix changes the return value format and is only implemented for
recently created gexiv2_metadata_try_get_tag_multiple(). For backwards
compatibility, the old format is preserved in
gexiv2_metadata_get_tag_multiple().
Changes:
* Create gexiv2_metadata_get_xmp_tag_multiple_deprecated() to preserve
the existing format. Change gexiv2_metadata_get_tag_multiple() to use
this function.
* Fix gexiv2_metadata_try_get_xml_tag_multiple() to return correct
values when tag is of type xmpText and xmpAlt.
* Added documentation to gexiv2-metadata.h explaining returns values.
* Change NULL to nullptr as part of modernisation.
gexiv2/gexiv2-metadata-private.h | 1 +
gexiv2/gexiv2-metadata-xmp.cpp | 114 +++++++++++++++++++++++++++++++++------
gexiv2/gexiv2-metadata.cpp | 14 +++--
gexiv2/gexiv2-metadata.h | 10 +++-
4 files changed, 118 insertions(+), 21 deletions(-)
---
diff --git a/gexiv2/gexiv2-metadata-private.h b/gexiv2/gexiv2-metadata-private.h
index e6c96fa..e377c6f 100644
--- a/gexiv2/gexiv2-metadata-private.h
+++ b/gexiv2/gexiv2-metadata-private.h
@@ -83,6 +83,7 @@ G_GNUC_INTERNAL gchar*
gexiv2_metadata_get_xmp_tag_interpreted_string (GExiv2M
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, GError **error);
+G_GNUC_INTERNAL gchar** gexiv2_metadata_get_xmp_tag_multiple_deprecated
(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);
diff --git a/gexiv2/gexiv2-metadata-xmp.cpp b/gexiv2/gexiv2-metadata-xmp.cpp
index fcc48b4..a1c9236 100644
--- a/gexiv2/gexiv2-metadata-xmp.cpp
+++ b/gexiv2/gexiv2-metadata-xmp.cpp
@@ -275,38 +275,122 @@ 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, 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();
-
+gchar** gexiv2_metadata_get_xmp_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 != nullptr, nullptr);
+ g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+ g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
+ gchar** array = nullptr; // Return value
+
try {
+ Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+
+ const Exiv2::XmpKey key = Exiv2::XmpKey(tag);
+ auto it = xmp_data.findKey(key);
+
+ while (it != xmp_data.end() && it->count() == 0 && it->key() != key.key())
+ it++;
+
+ if (it != xmp_data.end()) {
+ if (it->typeId() == Exiv2::TypeId::xmpText) {
+ // xmpText tags only have single value
+ array = g_new(gchar*, 2);
+ array[1] = nullptr;
+
+ array[0] = g_strdup(it->toString().c_str());
+ } else if (it->typeId() == Exiv2::TypeId::langAlt) {
+ // For langAlt types, it->count() returns the number of
+ // items but it->toString(i) ONLY returns the default
+ // value (if any) minus the "lang=x-default " prefix.
+ //
+ // Instead use it->toString() and parse the result to
+ // create the return array.
+ // (Issue #61 - https://gitlab.gnome.org/GNOME/gexiv2/-/issues/61)
+
+ auto num_items = it->count();
+
+ if (!num_items) {
+ // Empty string
+ array = g_new(gchar*, 2);
+ array[1] = nullptr;
+ array[0] = g_strdup("");
+ } else {
+ const int SEPARATOR = 2; // ", "
+ const std::string temp = it->toString();
+ std::string::size_type pos1 = 0;
+ std::string::size_type pos2 = temp.find(',', pos1);
+
+ array = g_new(gchar*, num_items + 1);
+ array[num_items] = nullptr;
+
+ for (decltype(num_items) i = 0; i < num_items; i++) {
+ array[i] = g_strdup(temp.substr(pos1, pos2 - pos1).c_str());
+ pos1 = pos2 + SEPARATOR;
+ pos2 = temp.find(',', pos1);
+ }
+ }
+ } else {
+ // For Xmp structures, cycle through all elements and
+ // add to return array
+
+ auto num_items = it->count();
+
+ array = g_new(gchar*, num_items + 1);
+ array[num_items] = nullptr;
+
+ for (decltype(num_items) i = 0; i < num_items; i++)
+ array[i] = g_strdup(it->toString(i).c_str());
+ }
+ return array;
+ }
+ } catch (Exiv2::Error& e) {
+ if (array) {
+ g_strfreev(array);
+ }
+ g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+ }
+
+ array = g_new(gchar*, 1);
+ array[0] = nullptr;
+
+ return array;
+}
+
+gchar** gexiv2_metadata_get_xmp_tag_multiple_deprecated (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 != nullptr, nullptr);
+ g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+ g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
+ try {
+ Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+
Exiv2::XmpKey key = Exiv2::XmpKey(tag);
Exiv2::XmpData::iterator it = xmp_data.findKey(key);
while (it != xmp_data.end() && it->count() == 0 && it->key() != key.key())
it++;
-
+
if (it != xmp_data.end()) {
auto size = it->count ();
gchar **array = g_new (gchar*, size + 1);
- array[size] = NULL;
-
+ array[size] = nullptr;
+
for (decltype(size) i = 0; i < size; i++)
array[i] = g_strdup (it->toString (i).c_str ());
-
+
return array;
}
} catch (Exiv2::Error& e) {
g_set_error_literal (error, g_quark_from_string ("GExiv2"), e.code (), e.what ());
}
-
+
gchar **array = g_new (gchar*, 1);
- array[0] = NULL;
-
+ array[0] = nullptr;
+
return array;
}
diff --git a/gexiv2/gexiv2-metadata.cpp b/gexiv2/gexiv2-metadata.cpp
index f811792..991529d 100644
--- a/gexiv2/gexiv2-metadata.cpp
+++ b/gexiv2/gexiv2-metadata.cpp
@@ -1126,15 +1126,21 @@ gboolean gexiv2_metadata_try_set_tag_multiple(GExiv2Metadata *self, const gchar*
return FALSE;
}
-gchar** gexiv2_metadata_get_tag_multiple(GExiv2Metadata *self, const gchar* tag) {
- gchar **tags = nullptr;
- GError *error = nullptr;
+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 != nullptr, nullptr);
g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
- tags = gexiv2_metadata_try_get_tag_multiple(self, tag, &error);
+ if (gexiv2_metadata_is_xmp_tag(tag))
+ tags = gexiv2_metadata_get_xmp_tag_multiple_deprecated(self, tag, &error);
+ else if (gexiv2_metadata_is_exif_tag(tag))
+ tags = gexiv2_metadata_get_exif_tag_multiple(self, tag, &error);
+ else if (gexiv2_metadata_is_iptc_tag(tag))
+ tags = gexiv2_metadata_get_iptc_tag_multiple(self, tag, &error);
if (error) {
g_warning("%s", error->message);
diff --git a/gexiv2/gexiv2-metadata.h b/gexiv2/gexiv2-metadata.h
index 9b26f4c..dceeb7e 100644
--- a/gexiv2/gexiv2-metadata.h
+++ b/gexiv2/gexiv2-metadata.h
@@ -614,7 +614,9 @@ 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>
*
* Returns: (transfer full) (allow-none) (array zero-terminated=1): The multiple string values of
- * the tag
+ * the tag. Returns NULL if parameters are NULL or @tag does not begin with recognised type of
+ * metadata ("Exif.", "Xmp." or "Iptc."). For a well formed @tag, returns array[0] = NULL if @tag
+ * is undefined or is not set in the current metadata.
*
* Since: 0.12.2
*/
@@ -647,7 +649,11 @@ gboolean gexiv2_metadata_try_set_tag_multiple (GExiv2Metadata *self, const
gcha
* control if and how the error is outputted.
*
* Returns: (transfer full) (allow-none) (array zero-terminated=1): The multiple string values of
- * the tag
+ * the tag. Returns NULL if parameters are NULL or @tag does not begin with recognised type of
+ * metadata ("Exif.", "Xmp." or "Iptc."). For a well formed @tag, returns array[0] = NULL if @tag
+ * is undefined or is not set in the current metadata.
+ * (Note: <ulink url="https://gitlab.gnome.org/GNOME/gexiv2/-/issues/61">xmpText/langAlt bug</ulink>
+ * is fixed in gexiv2_metadata_try_get_tag_multiple())
*
* Deprecated: 0.12.2: Use gexiv2_metadata_try_get_tag_multiple() instead.
*/
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]