[gexiv2/wip/58: 19/19] Fix ordering of XMP tags
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gexiv2/wip/58: 19/19] Fix ordering of XMP tags
- Date: Mon, 30 Nov 2020 22:00:41 +0000 (UTC)
commit 41ed229cd1e43327e5d7411c2f825545d1c1a69a
Author: Jens Georg <mail jensge org>
Date: Sat Nov 14 14:57:15 2020 +0100
Fix ordering of XMP tags
Use natural collation for the keys so that e.g. 10 is sorted after 9 and not
between 1 and to
Fixes #58
gexiv2/gexiv2-metadata-xmp.cpp | 57 ++++++++++++++++++++++++++++++++++++------
gexiv2/meson.build | 1 +
2 files changed, 51 insertions(+), 7 deletions(-)
---
diff --git a/gexiv2/gexiv2-metadata-xmp.cpp b/gexiv2/gexiv2-metadata-xmp.cpp
index 87795a4..0713418 100644
--- a/gexiv2/gexiv2-metadata-xmp.cpp
+++ b/gexiv2/gexiv2-metadata-xmp.cpp
@@ -8,11 +8,14 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
-#include "gexiv2-metadata.h"
#include "gexiv2-metadata-private.h"
-#include <string>
-#include <glib-object.h>
+#include "gexiv2-metadata.h"
+
#include <exiv2/exiv2.hpp>
+#include <glib-object.h>
+#include <iostream>
+#include <locale>
+#include <string>
G_BEGIN_DECLS
@@ -96,14 +99,53 @@ gboolean gexiv2_metadata_clear_xmp_tag(GExiv2Metadata *self, const gchar* tag) {
return erased;
}
+// Port of the NaturalCollate.vala collation key generation to C++
+// Simplified to assume that all XMP keys are ASCII and not UTF-8
+// Original source:
+// https://gitlab.gnome.org/GNOME/shotwell/-/blob/master/src/NaturalCollate.vala
+static std::string collate_key(const std::string& str) {
+ constexpr char SUPERDIGIT = ':';
+ constexpr char COLLATION_SENTINAL[] = "\x01\x01\x01";
+ constexpr char NUM_SENTINEL = 0x2;
+
+ std::stringstream in{str};
+ std::stringstream out{};
+
+ while (not in.eof()) {
+ // As long as there are no digits, we put them from input to output
+ while (not std::isdigit(in.peek()) && not in.eof()) {
+ out << static_cast<char>(in.get());
+ }
+
+ if (not in.eof()) {
+
+ // We read the number (integer only)...
+ uint64_t number;
+ in >> number;
+
+ std::string to_append(std::to_string(number).length(), SUPERDIGIT);
+
+ // ... and append it together with its length in : to the output
+ out << COLLATION_SENTINAL << NUM_SENTINEL << to_append << number;
+ }
+ }
+
+ // Add a sentinal for good measure (no idea, follows the original code)
+ out << NUM_SENTINEL;
+
+ return out.str();
+}
+
gchar** gexiv2_metadata_get_xmp_tags (GExiv2Metadata *self) {
g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
// get a copy of the original XmpData and sort it by key, preserving the original
Exiv2::XmpData xmp_data = Exiv2::XmpData(self->priv->image->xmpData());
- xmp_data.sortByKey ();
-
+ std::sort(xmp_data.begin(), xmp_data.end(), [](Exiv2::Xmpdatum& a, Exiv2::Xmpdatum& b) {
+ return collate_key(a.key()) <= collate_key(b.key());
+ });
+
GSList *list = NULL;
GSList *list_iter;
gchar** data;
@@ -115,11 +157,12 @@ gchar** gexiv2_metadata_get_xmp_tags (GExiv2Metadata *self) {
count++;
}
}
-
+
data = g_new (gchar*, count + 1);
data[count --] = NULL;
- for (list_iter = list; list_iter != NULL; list_iter = list_iter->next)
+ for (list_iter = list; list_iter != NULL; list_iter = list_iter->next) {
data[count--] = static_cast<gchar*>(list_iter->data);
+ }
g_slist_free (list);
diff --git a/gexiv2/meson.build b/gexiv2/meson.build
index 12abf92..c737431 100644
--- a/gexiv2/meson.build
+++ b/gexiv2/meson.build
@@ -54,6 +54,7 @@ gexiv2 = library('gexiv2',
'gexiv2-log-private.h',
'gexiv2-metadata-private.h',
'gexiv2-stream-io.h',
+ 'NaturalCollate.c',
'gexiv2-preview-properties-private.h',
'gexiv2-preview-image-private.h'] +
gexiv2_headers +
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]