[glib] g_date_time_format_locale: ensure locale encoding is used



commit 6a1e8e8fa70fdd734b79ae3b5e2bf9ab64a31c90
Author: Руслан Ижбулатов <lrn1986 gmail com>
Date:   Sat May 7 17:02:55 2016 +0000

    g_date_time_format_locale: ensure locale encoding is used
    
    Fallback code for g_date_time_format_locale() fetches translated
    strings (such as day and month names) from .mo catalogues via
    gettext. These strings always come in UTF-8 encoding, because
    that is the encoding that glib sets when it initializes gettext
    for itself.
    However, the non-fallback code uses nl_langinfo() and expects
    its results to be in locale-dependent encoding.
    
    This mismatch can result in UTF-8 strings being converted to UTF-8,
    producing gibberish.
    
    Fix this by converting UTF-8 strings to locale-dependent encoding
    before using them. Also fix the code that was already doing the locale->UTF-8
    conversion to not convert the strings when they are already UTF-8-encoded.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=766092

 glib/gdatetime.c |  111 +++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 98 insertions(+), 13 deletions(-)
---
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
index ebc4837..8ff0223 100644
--- a/glib/gdatetime.c
+++ b/glib/gdatetime.c
@@ -2241,11 +2241,13 @@ g_date_time_format_locale (GDateTime   *datetime,
   guint     len;
   guint     colons;
   gchar    *tmp;
+  gsize     tmp_len;
   gunichar  c;
   gboolean  alt_digits = FALSE;
   gboolean  pad_set = FALSE;
   gchar    *pad = "";
   gchar    *ampm;
+  const gchar *name;
   const gchar *tz;
 
   while (*format)
@@ -2257,10 +2259,10 @@ g_date_time_format_locale (GDateTime   *datetime,
            g_string_append_len (outstr, format, len);
          else
            {
-             tmp = g_locale_from_utf8 (format, len, NULL, NULL, NULL);
+             tmp = g_locale_from_utf8 (format, len, NULL, &tmp_len, NULL);
              if (!tmp)
                return FALSE;
-             g_string_append (outstr, tmp);
+             g_string_append_len (outstr, tmp, tmp_len);
              g_free (tmp);
            }
        }
@@ -2284,16 +2286,72 @@ g_date_time_format_locale (GDateTime   *datetime,
       switch (c)
        {
        case 'a':
-         g_string_append (outstr, WEEKDAY_ABBR (datetime));
+         name = WEEKDAY_ABBR (datetime);
+#if !defined (HAVE_LANGINFO_TIME)
+         if (!locale_is_utf8)
+           {
+             tmp = g_locale_from_utf8 (name, -1, NULL, &tmp_len, NULL);
+             if (!tmp)
+               return FALSE;
+             g_string_append_len (outstr, tmp, tmp_len);
+             g_free (tmp);
+           }
+         else
+#endif
+           {
+             g_string_append (outstr, name);
+           }
          break;
        case 'A':
-         g_string_append (outstr, WEEKDAY_FULL (datetime));
+         name = WEEKDAY_FULL (datetime);
+#if !defined (HAVE_LANGINFO_TIME)
+         if (!locale_is_utf8)
+           {
+             tmp = g_locale_from_utf8 (name, -1, NULL, &tmp_len, NULL);
+             if (!tmp)
+               return FALSE;
+             g_string_append_len (outstr, tmp, tmp_len);
+             g_free (tmp);
+           }
+         else
+#endif
+           {
+             g_string_append (outstr, name);
+           }
          break;
        case 'b':
-         g_string_append (outstr, MONTH_ABBR (datetime));
+         name = MONTH_ABBR (datetime);
+#if !defined (HAVE_LANGINFO_TIME)
+         if (!locale_is_utf8)
+           {
+             tmp = g_locale_from_utf8 (name, -1, NULL, &tmp_len, NULL);
+             if (!tmp)
+               return FALSE;
+             g_string_append_len (outstr, tmp, tmp_len);
+             g_free (tmp);
+           }
+         else
+#endif
+           {
+             g_string_append (outstr, name);
+           }
          break;
        case 'B':
-         g_string_append (outstr, MONTH_FULL (datetime));
+         name = MONTH_FULL (datetime);
+#if !defined (HAVE_LANGINFO_TIME)
+         if (!locale_is_utf8)
+           {
+             tmp = g_locale_from_utf8 (name, -1, NULL, &tmp_len, NULL);
+             if (!tmp)
+               return FALSE;
+             g_string_append_len (outstr, tmp, tmp_len);
+             g_free (tmp);
+           }
+         else
+#endif
+           {
+             g_string_append (outstr, name);
+           }
          break;
        case 'c':
          {
@@ -2329,7 +2387,21 @@ g_date_time_format_locale (GDateTime   *datetime,
                         g_date_time_get_week_numbering_year (datetime));
          break;
        case 'h':
-         g_string_append (outstr, MONTH_ABBR (datetime));
+         name = MONTH_ABBR (datetime);
+#if !defined (HAVE_LANGINFO_TIME)
+         if (!locale_is_utf8)
+           {
+             tmp = g_locale_from_utf8 (name, -1, NULL, &tmp_len, NULL);
+             if (!tmp)
+               return FALSE;
+             g_string_append_len (outstr, tmp, tmp_len);
+             g_free (tmp);
+           }
+         else
+#endif
+           {
+             g_string_append (outstr, name);
+           }
          break;
        case 'H':
          format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
@@ -2367,44 +2439,56 @@ g_date_time_format_locale (GDateTime   *datetime,
          goto next_mod;
        case 'p':
          ampm = (gchar *) GET_AMPM (datetime);
+#if defined (HAVE_LANGINFO_TIME)
          if (!locale_is_utf8)
            {
+             /* This assumes that locale encoding can't have embedded NULs */
              ampm = tmp = g_locale_to_utf8 (ampm, -1, NULL, NULL, NULL);
              if (!tmp)
                return FALSE;
            }
+#endif
          ampm = g_utf8_strup (ampm, -1);
+         tmp_len = strlen (ampm);
          if (!locale_is_utf8)
            {
+#if defined (HAVE_LANGINFO_TIME)
              g_free (tmp);
-             tmp = g_locale_from_utf8 (ampm, -1, NULL, NULL, NULL);
+#endif
+             tmp = g_locale_from_utf8 (ampm, -1, NULL, &tmp_len, NULL);
              g_free (ampm);
              if (!tmp)
                return FALSE;
              ampm = tmp;
            }
-         g_string_append (outstr, ampm);
+         g_string_append_len (outstr, ampm, tmp_len);
          g_free (ampm);
          break;
        case 'P':
          ampm = (gchar *) GET_AMPM (datetime);
+#if defined (HAVE_LANGINFO_TIME)
          if (!locale_is_utf8)
            {
+             /* This assumes that locale encoding can't have embedded NULs */
              ampm = tmp = g_locale_to_utf8 (ampm, -1, NULL, NULL, NULL);
              if (!tmp)
                return FALSE;
            }
+#endif
          ampm = g_utf8_strdown (ampm, -1);
+         tmp_len = strlen (ampm);
          if (!locale_is_utf8)
            {
+#if defined (HAVE_LANGINFO_TIME)
              g_free (tmp);
-             tmp = g_locale_from_utf8 (ampm, -1, NULL, NULL, NULL);
+#endif
+             tmp = g_locale_from_utf8 (ampm, -1, NULL, &tmp_len, NULL);
              g_free (ampm);
              if (!tmp)
                return FALSE;
              ampm = tmp;
            }
-         g_string_append (outstr, ampm);
+         g_string_append_len (outstr, ampm, tmp_len);
          g_free (ampm);
          break;
        case 'r':
@@ -2482,13 +2566,14 @@ g_date_time_format_locale (GDateTime   *datetime,
          break;
        case 'Z':
          tz = g_date_time_get_timezone_abbreviation (datetime);
+         tmp_len = strlen (tz);
          if (!locale_is_utf8)
            {
-             tz = tmp = g_locale_from_utf8 (tz, -1, NULL, NULL, NULL);
+             tz = tmp = g_locale_from_utf8 (tz, -1, NULL, &tmp_len, NULL);
              if (!tmp)
                return FALSE;
            }
-         g_string_append (outstr, tz);
+         g_string_append_len (outstr, tz, tmp_len);
          if (!locale_is_utf8)
            g_free (tmp);
          break;


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