[network-manager-openvpn/th/utf8safe-bgo763039: 3/5] utils: add nmv_utils_str_utf8safe_escape()



commit c3fee4ad73e39dcf2e41db76cd4bc7fec2cde3de
Author: Thomas Haller <thaller redhat com>
Date:   Thu Mar 3 10:15:09 2016 +0100

    utils: add nmv_utils_str_utf8safe_escape()

 properties/tests/test-import-export.c |   78 +++++++++++++++++++++++
 shared/utils.c                        |  109 +++++++++++++++++++++++++++++++++
 shared/utils.h                        |    5 ++
 3 files changed, 192 insertions(+), 0 deletions(-)
---
diff --git a/properties/tests/test-import-export.c b/properties/tests/test-import-export.c
index 763e785..612675a 100644
--- a/properties/tests/test-import-export.c
+++ b/properties/tests/test-import-export.c
@@ -31,6 +31,7 @@
 #include "nm-openvpn.h"
 #include "nm-openvpn-service-defines.h"
 #include "import-export.h"
+#include "utils.h"
 
 #include "nm-test-utils.h"
 
@@ -1302,6 +1303,81 @@ test_args_parse_line (void)
 
 /*****************************************************************************/
 
+static void
+do_test_utils_str_utf8safe (const char *str, const char *expected)
+{
+       const char *str_safe, *s;
+       gs_free char *str2 = NULL;
+       gs_free char *str3 = NULL;
+
+       str_safe = nmv_utils_str_utf8safe_escape_c (str, &str2);
+
+       str3 = nmv_utils_str_utf8safe_escape (str);
+       g_assert_cmpstr (str3, ==, str_safe);
+       g_assert ((!str && !str3) || (str != str3));
+       g_clear_pointer (&str3, g_free);
+
+       if (expected == NULL) {
+               g_assert (str_safe == str);
+               g_assert (!str2);
+               if (str) {
+                       g_assert (!strchr (str, '\\'));
+                       g_assert (g_utf8_validate (str, -1, NULL));
+               }
+
+               g_assert (str == nmv_utils_str_utf8safe_unescape_c (str_safe, &str3));
+               g_assert (!str3);
+
+               str3 = nmv_utils_str_utf8safe_unescape (str_safe);
+               if (str) {
+                       g_assert (str3 != str);
+                       g_assert_cmpstr (str3, ==, str);
+               } else
+                       g_assert (!str3);
+               g_clear_pointer (&str3, g_free);
+               return;
+       }
+
+       g_assert (str);
+       g_assert (str_safe != str);
+       g_assert (str_safe == str2);
+       g_assert (strchr (str, '\\') || !g_utf8_validate (str, -1, NULL));
+       g_assert (g_utf8_validate (str_safe, -1, NULL));
+
+       str3 = g_strcompress (str_safe);
+       g_assert_cmpstr (str, ==, str3);
+       g_clear_pointer (&str3, g_free);
+
+       str3 = nmv_utils_str_utf8safe_unescape (str_safe);
+       g_assert (str3 != str);
+       g_assert_cmpstr (str3, ==, str);
+       g_clear_pointer (&str3, g_free);
+
+       s = nmv_utils_str_utf8safe_unescape_c (str_safe, &str3);
+       g_assert (str3 != str);
+       g_assert (s == str3);
+       g_assert_cmpstr (str3, ==, str);
+       g_clear_pointer (&str3, g_free);
+
+       g_assert_cmpstr (str_safe, ==, expected);
+}
+
+static void
+test_utils_str_utf8safe (void)
+{
+       do_test_utils_str_utf8safe (NULL, NULL);
+       do_test_utils_str_utf8safe ("", NULL);
+       do_test_utils_str_utf8safe ("a", NULL);
+       do_test_utils_str_utf8safe ("ab", NULL);
+       do_test_utils_str_utf8safe ("abäb", NULL);
+       do_test_utils_str_utf8safe ("㈞abä㈞b", NULL);
+       do_test_utils_str_utf8safe ("Äab\\äb", "Äab\\\\äb");
+       do_test_utils_str_utf8safe ("ÄÄab\\äb", "ÄÄab\\\\äb");
+       do_test_utils_str_utf8safe ("Ä\304ab\\äb", "Ä\\304ab\\\\äb");
+}
+
+/*****************************************************************************/
+
 NMTST_DEFINE ();
 
 int main (int argc, char **argv)
@@ -1376,6 +1452,8 @@ int main (int argc, char **argv)
 
        _add_test_func_simple (test_args_parse_line);
 
+       _add_test_func_simple (test_utils_str_utf8safe);
+
        result = g_test_run ();
        if (result != EXIT_SUCCESS)
                return result;
diff --git a/shared/utils.c b/shared/utils.c
index b777d9f..0c2cb3f 100644
--- a/shared/utils.c
+++ b/shared/utils.c
@@ -170,3 +170,112 @@ _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 ma
 
 /*****************************************************************************/
 
+/**
+ * nmv_utils_str_utf8safe_escape:
+ * @str: NUL terminated input string, possibly in utf-8 encoding
+ *
+ * Does something similar like g_strescape(), where the operation
+ * can be reverted by g_strcompress(). However, the UTF-8 characters
+ * are not escaped at all (except the escape character '\\'). It only
+ * escapes non-UTF-8 characters. This way it is possible to transfer
+ * the string as UTF-8 via D-Bus.
+ * Also, it can be directly displayed to the user and will show as
+ * UTF-8, with exception of the escape character and characters in
+ * different encodings.
+ *
+ * Returns: the escaped input string in UTF-8 encoding. The returned
+ *   value should be freed with g_free().
+ *   The escaping can be reverted by g_strcompress().
+ **/
+char *
+nmv_utils_str_utf8safe_escape (const char *str)
+{
+       char *s = NULL;
+
+       nmv_utils_str_utf8safe_escape_c (str, &s);
+       return s ? : g_strdup (str);
+}
+
+/**
+ * nmv_utils_str_utf8safe_escape_c:
+ * @str: NUL terminated input string, possibly in utf-8 encoding
+ * @str_free: (out): return the pointer location of the string
+ *   if a copying was necessary.
+ *
+ * Like nmv_utils_str_utf8safe_escape(), except that the string
+ * is only copied if it is actually necessary. In that case,
+ * @str_free will contain the allocated string which must be
+ * freed with g_free().
+ * Otherwise, @str_free is %NULL and the input string is returned.
+ *
+ * Returns: the escaped input string. If no escaping is necessary,
+ *   it returns @str. Otherwise, an allocated string @str_free is
+ *   returned.
+ *   The escaping can be reverted by g_strcompress().
+ **/
+const char *
+nmv_utils_str_utf8safe_escape_c (const char *str, char **str_free)
+{
+       const char *p = NULL;
+       guchar ch;
+       GString *s;
+
+       g_return_val_if_fail (str_free, NULL);
+
+       *str_free = NULL;
+       if (!str || !str[0])
+               return str;
+
+       if (g_utf8_validate (str, -1, &p)) {
+               if (!strchr (str, '\\'))
+                       return str;
+       }
+
+       s = g_string_sized_new (30);
+
+       do {
+               for (; str < p; str++) {
+                       if (str[0] == '\\')
+                               g_string_append (s, "\\\\");
+                       else
+                               g_string_append_c (s, str[0]);
+               }
+
+               ch = p[0];
+               if (ch == '\0')
+                       break;
+               g_string_append_c (s, '\\');
+               g_string_append_c (s, '0' + ((ch >> 6) & 07));
+               g_string_append_c (s, '0' + ((ch >> 3) & 07));
+               g_string_append_c (s, '0' + ( ch       & 07));
+
+               str = &p[1];
+               g_utf8_validate (str, -1, &p);
+       } while (TRUE);
+
+       *str_free = g_string_free (s, FALSE);
+       return *str_free;
+}
+
+char *
+nmv_utils_str_utf8safe_unescape (const char *str)
+{
+       if (!str)
+               return NULL;
+       return g_strcompress (str);
+}
+
+const char *
+nmv_utils_str_utf8safe_unescape_c (const char *str, char **str_free)
+{
+       g_return_val_if_fail (str_free, NULL);
+
+       *str_free = NULL;
+       if (!str || !strchr (str, '\\'))
+               return str;
+       *str_free =  g_strcompress (str);
+       return *str_free;
+}
+
+/*****************************************************************************/
+
diff --git a/shared/utils.h b/shared/utils.h
index 4571a77..3853c6c 100644
--- a/shared/utils.h
+++ b/shared/utils.h
@@ -30,5 +30,10 @@ gboolean is_encrypted (const char *filename);
 
 gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback);
 
+char *      nmv_utils_str_utf8safe_escape     (const char *str);
+const char *nmv_utils_str_utf8safe_escape_c   (const char *str, char **out_clone);
+char *      nmv_utils_str_utf8safe_unescape   (const char *str);
+const char *nmv_utils_str_utf8safe_unescape_c (const char *str, char **str_free);
+
 #endif  /* UTILS_H */
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]