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 len;
guint colons; guint colons;
gchar *tmp; gchar *tmp;
gsize tmp_len;
gunichar c; gunichar c;
gboolean alt_digits = FALSE; gboolean alt_digits = FALSE;
gboolean pad_set = FALSE; gboolean pad_set = FALSE;
gchar *pad = ""; gchar *pad = "";
gchar *ampm; gchar *ampm;
const gchar *name;
const gchar *tz; const gchar *tz;
while (*format) while (*format)
@ -2257,10 +2259,10 @@ g_date_time_format_locale (GDateTime *datetime,
g_string_append_len (outstr, format, len); g_string_append_len (outstr, format, len);
else else
{ {
tmp = g_locale_from_utf8 (format, len, NULL, NULL, NULL); tmp = g_locale_from_utf8 (format, len, NULL, &tmp_len, NULL);
if (!tmp) if (!tmp)
return FALSE; return FALSE;
g_string_append (outstr, tmp); g_string_append_len (outstr, tmp, tmp_len);
g_free (tmp); g_free (tmp);
} }
} }
@ -2284,16 +2286,72 @@ g_date_time_format_locale (GDateTime *datetime,
switch (c) switch (c)
{ {
case 'a': 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; break;
case 'A': 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; break;
case 'b': 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; break;
case 'B': 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; break;
case 'c': case 'c':
{ {
@ -2329,7 +2387,21 @@ g_date_time_format_locale (GDateTime *datetime,
g_date_time_get_week_numbering_year (datetime)); g_date_time_get_week_numbering_year (datetime));
break; break;
case 'h': 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; break;
case 'H': case 'H':
format_number (outstr, alt_digits, pad_set ? pad : "0", 2, format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
@ -2367,44 +2439,56 @@ g_date_time_format_locale (GDateTime *datetime,
goto next_mod; goto next_mod;
case 'p': case 'p':
ampm = (gchar *) GET_AMPM (datetime); ampm = (gchar *) GET_AMPM (datetime);
#if defined (HAVE_LANGINFO_TIME)
if (!locale_is_utf8) 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); ampm = tmp = g_locale_to_utf8 (ampm, -1, NULL, NULL, NULL);
if (!tmp) if (!tmp)
return FALSE; return FALSE;
} }
#endif
ampm = g_utf8_strup (ampm, -1); ampm = g_utf8_strup (ampm, -1);
tmp_len = strlen (ampm);
if (!locale_is_utf8) if (!locale_is_utf8)
{ {
#if defined (HAVE_LANGINFO_TIME)
g_free (tmp); 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); g_free (ampm);
if (!tmp) if (!tmp)
return FALSE; return FALSE;
ampm = tmp; ampm = tmp;
} }
g_string_append (outstr, ampm); g_string_append_len (outstr, ampm, tmp_len);
g_free (ampm); g_free (ampm);
break; break;
case 'P': case 'P':
ampm = (gchar *) GET_AMPM (datetime); ampm = (gchar *) GET_AMPM (datetime);
#if defined (HAVE_LANGINFO_TIME)
if (!locale_is_utf8) 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); ampm = tmp = g_locale_to_utf8 (ampm, -1, NULL, NULL, NULL);
if (!tmp) if (!tmp)
return FALSE; return FALSE;
} }
#endif
ampm = g_utf8_strdown (ampm, -1); ampm = g_utf8_strdown (ampm, -1);
tmp_len = strlen (ampm);
if (!locale_is_utf8) if (!locale_is_utf8)
{ {
#if defined (HAVE_LANGINFO_TIME)
g_free (tmp); 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); g_free (ampm);
if (!tmp) if (!tmp)
return FALSE; return FALSE;
ampm = tmp; ampm = tmp;
} }
g_string_append (outstr, ampm); g_string_append_len (outstr, ampm, tmp_len);
g_free (ampm); g_free (ampm);
break; break;
case 'r': case 'r':
@ -2482,13 +2566,14 @@ g_date_time_format_locale (GDateTime *datetime,
break; break;
case 'Z': case 'Z':
tz = g_date_time_get_timezone_abbreviation (datetime); tz = g_date_time_get_timezone_abbreviation (datetime);
tmp_len = strlen (tz);
if (!locale_is_utf8) 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) if (!tmp)
return FALSE; return FALSE;
} }
g_string_append (outstr, tz); g_string_append_len (outstr, tz, tmp_len);
if (!locale_is_utf8) if (!locale_is_utf8)
g_free (tmp); g_free (tmp);
break; break;