diff --git a/ChangeLog b/ChangeLog index cdaedebe5..d06f120d4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2005-04-27 Tor Lillqvist + + * glib/gconvert.c (open_converter, g_convert_with_iconv): Don't + call g_set_error() unless the GError pointer is non-NULL. This + avoids infinite recursion problems in certain rare situations on + Windows, when g_locale_from_utf8() is called from + _glib_get_locale_dir() after the change below. It's the + _glib_gettext() calls to translate error messages that are + parameters to g_set_error() that cause the recursion, not + g_set_error() itself. + + * glib/gwin32.c (g_win32_locale_filename_from_utf8): New + function. Converts a filename to the system codepage, and if a + straight conversion isn't possible (because the filename contains + characters not in the system codepage), try looking up the + filename (which should refer to an existing file for this to + succeed) with short (8.3) pathname components. + + * glib/gutils.c (_glib_get_locale_dir): No need to cache the + result, this function is normally called only once. Return the + path to the locale directory in system codepage, not UTF-8. The + path is passed to bindtextdomain(), which doesn't use UTF-8 file + names. Use g_win32_locale_filename_from_utf8(). (#301772) + + Don't do run-time lookup of message catalog directory on + Cygwin. Cygwin is supposed to look and feel like Unix, and on Unix + we use paths fixed at configure time. + 2005-04-19 Tor Lillqvist * glib/gutils.h: Minor comment improvement. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index cdaedebe5..d06f120d4 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,31 @@ +2005-04-27 Tor Lillqvist + + * glib/gconvert.c (open_converter, g_convert_with_iconv): Don't + call g_set_error() unless the GError pointer is non-NULL. This + avoids infinite recursion problems in certain rare situations on + Windows, when g_locale_from_utf8() is called from + _glib_get_locale_dir() after the change below. It's the + _glib_gettext() calls to translate error messages that are + parameters to g_set_error() that cause the recursion, not + g_set_error() itself. + + * glib/gwin32.c (g_win32_locale_filename_from_utf8): New + function. Converts a filename to the system codepage, and if a + straight conversion isn't possible (because the filename contains + characters not in the system codepage), try looking up the + filename (which should refer to an existing file for this to + succeed) with short (8.3) pathname components. + + * glib/gutils.c (_glib_get_locale_dir): No need to cache the + result, this function is normally called only once. Return the + path to the locale directory in system codepage, not UTF-8. The + path is passed to bindtextdomain(), which doesn't use UTF-8 file + names. Use g_win32_locale_filename_from_utf8(). (#301772) + + Don't do run-time lookup of message catalog directory on + Cygwin. Cygwin is supposed to look and feel like Unix, and on Unix + we use paths fixed at configure time. + 2005-04-19 Tor Lillqvist * glib/gutils.h: Minor comment improvement. diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index cdaedebe5..d06f120d4 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,31 @@ +2005-04-27 Tor Lillqvist + + * glib/gconvert.c (open_converter, g_convert_with_iconv): Don't + call g_set_error() unless the GError pointer is non-NULL. This + avoids infinite recursion problems in certain rare situations on + Windows, when g_locale_from_utf8() is called from + _glib_get_locale_dir() after the change below. It's the + _glib_gettext() calls to translate error messages that are + parameters to g_set_error() that cause the recursion, not + g_set_error() itself. + + * glib/gwin32.c (g_win32_locale_filename_from_utf8): New + function. Converts a filename to the system codepage, and if a + straight conversion isn't possible (because the filename contains + characters not in the system codepage), try looking up the + filename (which should refer to an existing file for this to + succeed) with short (8.3) pathname components. + + * glib/gutils.c (_glib_get_locale_dir): No need to cache the + result, this function is normally called only once. Return the + path to the locale directory in system codepage, not UTF-8. The + path is passed to bindtextdomain(), which doesn't use UTF-8 file + names. Use g_win32_locale_filename_from_utf8(). (#301772) + + Don't do run-time lookup of message catalog directory on + Cygwin. Cygwin is supposed to look and feel like Unix, and on Unix + we use paths fixed at configure time. + 2005-04-19 Tor Lillqvist * glib/gutils.h: Minor comment improvement. diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index cdaedebe5..d06f120d4 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,31 @@ +2005-04-27 Tor Lillqvist + + * glib/gconvert.c (open_converter, g_convert_with_iconv): Don't + call g_set_error() unless the GError pointer is non-NULL. This + avoids infinite recursion problems in certain rare situations on + Windows, when g_locale_from_utf8() is called from + _glib_get_locale_dir() after the change below. It's the + _glib_gettext() calls to translate error messages that are + parameters to g_set_error() that cause the recursion, not + g_set_error() itself. + + * glib/gwin32.c (g_win32_locale_filename_from_utf8): New + function. Converts a filename to the system codepage, and if a + straight conversion isn't possible (because the filename contains + characters not in the system codepage), try looking up the + filename (which should refer to an existing file for this to + succeed) with short (8.3) pathname components. + + * glib/gutils.c (_glib_get_locale_dir): No need to cache the + result, this function is normally called only once. Return the + path to the locale directory in system codepage, not UTF-8. The + path is passed to bindtextdomain(), which doesn't use UTF-8 file + names. Use g_win32_locale_filename_from_utf8(). (#301772) + + Don't do run-time lookup of message catalog directory on + Cygwin. Cygwin is supposed to look and feel like Unix, and on Unix + we use paths fixed at configure time. + 2005-04-19 Tor Lillqvist * glib/gutils.h: Minor comment improvement. diff --git a/glib/gconvert.c b/glib/gconvert.c index a2f97ef17..0f5f30b46 100644 --- a/glib/gconvert.c +++ b/glib/gconvert.c @@ -399,14 +399,17 @@ open_converter (const gchar *to_codeset, G_UNLOCK (iconv_cache_lock); /* Something went wrong. */ - if (errno == EINVAL) - g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_NO_CONVERSION, - _("Conversion from character set '%s' to '%s' is not supported"), - from_codeset, to_codeset); - else - g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED, - _("Could not open converter from '%s' to '%s'"), - from_codeset, to_codeset); + if (error) + { + if (errno == EINVAL) + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_NO_CONVERSION, + _("Conversion from character set '%s' to '%s' is not supported"), + from_codeset, to_codeset); + else + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED, + _("Could not open converter from '%s' to '%s'"), + from_codeset, to_codeset); + } return cd; } @@ -610,14 +613,16 @@ g_convert_with_iconv (const gchar *str, goto again; } case EILSEQ: - g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE, - _("Invalid byte sequence in conversion input")); + if (error) + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE, + _("Invalid byte sequence in conversion input")); have_error = TRUE; break; default: - g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED, - _("Error during conversion: %s"), - g_strerror (errno)); + if (error) + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED, + _("Error during conversion: %s"), + g_strerror (errno)); have_error = TRUE; break; } @@ -633,8 +638,9 @@ g_convert_with_iconv (const gchar *str, { if (!have_error) { - g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT, - _("Partial character sequence at end of input")); + if (error) + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT, + _("Partial character sequence at end of input")); have_error = TRUE; } } @@ -1122,7 +1128,7 @@ g_get_filename_charsets (G_CONST_RETURN gchar ***filename_charsets) gboolean g_get_filename_charsets (G_CONST_RETURN gchar ***filename_charsets) { - static gchar *charsets[] = { + static const gchar *charsets[] = { "UTF-8", NULL }; @@ -1190,8 +1196,9 @@ _g_convert_thread_init (void) * @error: location to store the error occuring, or %NULL to ignore * errors. Any of the errors in #GConvertError may occur. * - * Converts a string which is in the encoding used by GLib for filenames - * into a UTF-8 string. + * Converts a string which is in the encoding used by GLib for + * filenames into a UTF-8 string. Note that on Windows GLib uses UTF-8 + * for filenames. * * Return value: The converted string, or %NULL on an error. **/ @@ -1253,7 +1260,8 @@ g_filename_to_utf8 (const gchar *opsysstring, * @error: location to store the error occuring, or %NULL to ignore * errors. Any of the errors in #GConvertError may occur. * - * Converts a string from UTF-8 to the encoding used for filenames. + * Converts a string from UTF-8 to the encoding GLib uses for + * filenames. Note that on Windows GLib uses UTF-8 for filenames. * * Return value: The converted string, or %NULL on an error. **/ diff --git a/glib/gutils.c b/glib/gutils.c index 97d427cda..de3304cad 100644 --- a/glib/gutils.c +++ b/glib/gutils.c @@ -2781,23 +2781,46 @@ _g_utils_thread_init (void) #include -#ifdef G_PLATFORM_WIN32 +#ifdef G_OS_WIN32 +/** + * _glib_get_locale_dir: + * + * Return the path to the lib\locale subfolder of the GLib + * installation folder. The path is in the system codepage. We have to + * use system codepage as bindtextdomain() doesn't have a UTF-8 + * interface. + */ static const gchar * _glib_get_locale_dir (void) { - static const gchar *cache = NULL; - if (cache == NULL) - cache = g_win32_get_package_installation_subdirectory - (GETTEXT_PACKAGE, dll_name, "lib\\locale"); + gchar *dir, *cp_dir; + gchar *retval = NULL; - return cache; + dir = g_win32_get_package_installation_directory (GETTEXT_PACKAGE, dll_name); + cp_dir = g_win32_locale_filename_from_utf8 (dir); + g_free (dir); + + if (cp_dir) + { + /* Don't use g_build_filename() on pathnames in the system + * codepage. In CJK locales cp_dir might end with a double-byte + * character whose trailing byte is a backslash. + */ + retval = g_strconcat (cp_dir, "\\lib\\locale", NULL); + g_free (cp_dir); + } + + if (retval) + return retval; + else + return g_strdup (""); } #undef GLIB_LOCALE_DIR #define GLIB_LOCALE_DIR _glib_get_locale_dir () -#endif /* G_PLATFORM_WIN32 */ +#endif /* G_OS_WIN32 */ G_CONST_RETURN gchar * _glib_gettext (const gchar *str) diff --git a/glib/gwin32.c b/glib/gwin32.c index 79b90fc27..5cb32b04b 100644 --- a/glib/gwin32.c +++ b/glib/gwin32.c @@ -1223,7 +1223,7 @@ get_package_directory_from_module (gchar *module_name) * @dll_name was %NULL. * * If both @package and @dll_name are %NULL, the directory from where - * the main executable of the process was loaded is uses instead in + * the main executable of the process was loaded is used instead in * the same way as above. * * Returns: a string containing the installation directory for @@ -1467,5 +1467,59 @@ g_win32_get_windows_version (void) return windows_version; } +/** + * g_win32_locale_filename_from_utf8: + * + * @utf8filename: a UTF-8 encoded filename. + * + * Convertes a filename from UTF-8 to the system codepage. + * + * On NT-based Windows, on NTFS file systems, file names are in + * Unicode. It is quite possible that Unicode file names contain + * characters not representable in the system codepage. (For instance, + * Greek or Cyrillic characters on Western European or US Windows + * installations, or various less common CJK characters on CJK Windows + * installations.) + * + * In such a case, and if the filename refers to an existing file, and + * the file system stores alternate short (8.3) names for directory + * entries, the short form of the filename is returned. Note that the + * "short" name might in fact be longer than the Unicode name. If no + * system codepage name for the file is possible, NULL is returned. + * + * The return value is dynamically allocated and should be freed when + * no longer used. + * + * Return value: The converted filename, or %NULL on conversion + * failure and lack of short names. + * + * Since: 2.7 + */ +gchar * +g_win32_locale_filename_from_utf8 (const gchar *utf8filename) +{ + gchar *retval = g_locale_from_utf8 (utf8filename, -1, NULL, NULL, NULL); + + if (retval == NULL && G_WIN32_HAVE_WIDECHAR_API ()) + { + /* Conversion failed, so convert to wide chars, check if there + * is a 8.3 version, and use that. + */ + wchar_t *wname = g_utf8_to_utf16 (utf8filename, -1, NULL, NULL, NULL); + if (wname != NULL) + { + wchar_t wshortname[MAX_PATH + 1]; + if (GetShortPathNameW (wname, wshortname, G_N_ELEMENTS (wshortname))) + { + gchar *tem = g_utf16_to_utf8 (wshortname, -1, NULL, NULL, NULL); + retval = g_locale_from_utf8 (tem, -1, NULL, NULL, NULL); + g_free (tem); + } + g_free (wname); + } + } + return retval; +} + #define __G_WIN32_C__ #include "galiasdef.c" diff --git a/glib/gwin32.h b/glib/gwin32.h index 305025c22..481138dbb 100644 --- a/glib/gwin32.h +++ b/glib/gwin32.h @@ -91,6 +91,8 @@ gchar* g_win32_get_package_installation_subdirectory (gchar *package, guint g_win32_get_windows_version (void); +gchar* g_win32_locale_filename_from_utf8 (const gchar *utf8filename); + #define G_WIN32_IS_NT_BASED() (g_win32_get_windows_version () < 0x80000000) #define G_WIN32_HAVE_WIDECHAR_API() (G_WIN32_IS_NT_BASED ())