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
This commit is contained in:
Руслан Ижбулатов 2016-05-07 17:02:55 +00:00
parent 6055954a09
commit 6a1e8e8fa7

View File

@ -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;