[gexiv2/wip/58] Sort all meta-data (except exif) with collation
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gexiv2/wip/58] Sort all meta-data (except exif) with collation
- Date: Sun, 6 Dec 2020 20:17:26 +0000 (UTC)
commit 6ada2e8faebc68678273d9ab230491cc032bb724
Author: Jens Georg <mail jensge org>
Date: Sun Dec 6 21:16:07 2020 +0100
Sort all meta-data (except exif) with collation
Something is odd in ExifMetadata, it does not fulfil the requirements
for std::sort
gexiv2/gexiv2-metadata-exif.cpp | 14 ++++++++------
gexiv2/gexiv2-metadata-iptc.cpp | 2 +-
gexiv2/gexiv2-metadata-private.h | 17 ++++++++++++++++-
gexiv2/gexiv2-metadata-xmp.cpp | 41 +---------------------------------------
gexiv2/gexiv2-metadata.cpp | 40 +++++++++++++++++++++++++++++++++++++++
5 files changed, 66 insertions(+), 48 deletions(-)
---
diff --git a/gexiv2/gexiv2-metadata-exif.cpp b/gexiv2/gexiv2-metadata-exif.cpp
index 34d6d11..3b63fd9 100644
--- a/gexiv2/gexiv2-metadata-exif.cpp
+++ b/gexiv2/gexiv2-metadata-exif.cpp
@@ -67,15 +67,17 @@ void gexiv2_metadata_clear_exif (GExiv2Metadata *self) {
self->priv->image->exifData().clear ();
}
-gchar** gexiv2_metadata_get_exif_tags (GExiv2Metadata *self) {
- g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
- g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
-
+gchar** gexiv2_metadata_get_exif_tags(GExiv2Metadata* self) {
+ g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+ g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+
// get a copy of the ExifData and sort it by tags, preserving sort of original
Exiv2::ExifData exif_data = Exiv2::ExifData(self->priv->image->exifData());
exif_data.sortByKey();
-
- GSList *list = NULL;
+ // FIXME: Use detail::sortMetadata(exif_data);
+ // Something is not right in ExifData that makes std::sort fail
+
+ GSList* list = nullptr;
GSList *list_iter;
gchar** data;
gint count = 0;
diff --git a/gexiv2/gexiv2-metadata-iptc.cpp b/gexiv2/gexiv2-metadata-iptc.cpp
index 303d61a..4977126 100644
--- a/gexiv2/gexiv2-metadata-iptc.cpp
+++ b/gexiv2/gexiv2-metadata-iptc.cpp
@@ -74,7 +74,7 @@ gchar** gexiv2_metadata_get_iptc_tags(GExiv2Metadata* self) {
// get a copy of the IptcData and sort it by key, preserving the original
Exiv2::IptcData iptc_data = Exiv2::IptcData(self->priv->image->iptcData());
- iptc_data.sortByKey();
+ detail::sortMetadata(iptc_data);
GSList* list = nullptr;
GSList* list_iter = nullptr;
diff --git a/gexiv2/gexiv2-metadata-private.h b/gexiv2/gexiv2-metadata-private.h
index 7675945..e6c96fa 100644
--- a/gexiv2/gexiv2-metadata-private.h
+++ b/gexiv2/gexiv2-metadata-private.h
@@ -10,8 +10,23 @@
#ifndef GEXIV2_METADATA_PRIVATE_H
#define GEXIV2_METADATA_PRIVATE_H
-#include <gexiv2/gexiv2-metadata.h>
+#include <algorithm>
#include <exiv2/exiv2.hpp>
+#include <gexiv2/gexiv2-metadata.h>
+
+// Internal C++ functions, outside of G_BEGIN_DECLS
+// FIXME: Do we really need G_BEGIN_DECLS/END_DECLS for internal header?
+
+namespace detail {
+G_GNUC_INTERNAL std::string collate_key(const std::string& string);
+
+template<typename T>
+G_GNUC_INTERNAL void sortMetadata(T& container) {
+ std::sort(container.begin(), container.end(), [](Exiv2::Metadatum& a, Exiv2::Metadatum& b) {
+ return collate_key(a.key()) < collate_key(b.key());
+ });
+}
+}; // namespace detail
G_BEGIN_DECLS
diff --git a/gexiv2/gexiv2-metadata-xmp.cpp b/gexiv2/gexiv2-metadata-xmp.cpp
index 0713418..fcc48b4 100644
--- a/gexiv2/gexiv2-metadata-xmp.cpp
+++ b/gexiv2/gexiv2-metadata-xmp.cpp
@@ -99,52 +99,13 @@ 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());
- std::sort(xmp_data.begin(), xmp_data.end(), [](Exiv2::Xmpdatum& a, Exiv2::Xmpdatum& b) {
- return collate_key(a.key()) <= collate_key(b.key());
- });
+ detail::sortMetadata(xmp_data);
GSList *list = NULL;
GSList *list_iter;
diff --git a/gexiv2/gexiv2-metadata.cpp b/gexiv2/gexiv2-metadata.cpp
index 9338247..f811792 100644
--- a/gexiv2/gexiv2-metadata.cpp
+++ b/gexiv2/gexiv2-metadata.cpp
@@ -238,6 +238,46 @@ private:
}; // class GioIo
} // Anonymous namespace
+// -----------------------------------------------------------------------------
+// Misc internal helper functions
+
+// 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
+std::string detail::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();
+}
+
G_BEGIN_DECLS
G_DEFINE_TYPE_WITH_CODE (GExiv2Metadata, gexiv2_metadata, G_TYPE_OBJECT, G_ADD_PRIVATE (GExiv2Metadata));
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]