]> git.sesse.net Git - vlc/commitdiff
- Make FromLocale() usable any time (after setlocale()) - refs #838
authorRémi Denis-Courmont <rem@videolan.org>
Wed, 14 Mar 2007 17:30:00 +0000 (17:30 +0000)
committerRémi Denis-Courmont <rem@videolan.org>
Wed, 14 Mar 2007 17:30:00 +0000 (17:30 +0000)
- Fix re-entrancy problem for multiple LibVLC in the same process

src/libvlc-common.c
src/text/unicode.c

index c9119db10edeeab2283bd4ca755ce653e3673af3..6fb7558e99115b6a577669670b5d6d28a85a9312 100644 (file)
@@ -101,8 +101,6 @@ static volatile unsigned int i_instances = 0;
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-void LocaleInit( vlc_object_t * );
-void LocaleDeinit( void );
 static void SetLanguage   ( char const * );
 static inline int LoadMessages (void);
 static int  GetFilenames  ( libvlc_int_t *, int, char *[] );
@@ -277,12 +275,6 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc, char *ppsz_argv[] )
     setlocale( LC_CTYPE, "" );
     LoadMessages ();
 
-    /*
-     * Global iconv, must be done after setlocale()
-     * so that vlc_current_charset() works.
-     */
-    LocaleInit( (vlc_object_t *)p_libvlc );
-
     /* Translate "C" to the language code: "fr", "en_GB", "nl", "ru"... */
     msg_Dbg( p_libvlc, "translation test: code is \"%s\"", _("C") );
 
@@ -1052,9 +1044,6 @@ int libvlc_InternalDestroy( libvlc_int_t *p_libvlc, vlc_bool_t b_release )
     {
         /* System specific cleaning code */
         system_End( p_libvlc );
-
-       /* Destroy global iconv */
-        LocaleDeinit();
     }
     vlc_mutex_unlock( lockval.p_address );
     var_Destroy( p_libvlc_global, "libvlc" );
index 8b0323ade47b18bf5d57008388b1b70ffe05d886..3b8dfd5ac4623f36d61c8d0cb26f4b99f2eb4b74 100644 (file)
 # error No UTF8 charset conversion implemented on this platform!
 #endif
 
-typedef struct locale_data_t
-{
 #if defined (USE_ICONV)
-    vlc_iconv_t hd;
-    vlc_mutex_t lock;
-#elif defined (USE_MB2MB)
-    UINT fromCP;
-    UINT toCP;
-#endif
-} locale_data_t;
-
-static locale_data_t from_locale, to_locale;
-
+static char charset[sizeof ("CSISO11SWEDISHFORNAMES//translit")] = "";
 
-void LocaleInit( vlc_object_t *p_this )
+static void find_charset_once (void)
 {
-#if defined USE_ICONV
     char *psz_charset;
+    if (vlc_current_charset (&psz_charset)
+     || (psz_charset == NULL)
+     || ((size_t)snprintf (charset, sizeof (charset), "%s//translit",
+                           psz_charset) >= sizeof (charset)))
+        strcpy (charset, "UTF-8");
 
-    if( vlc_current_charset( &psz_charset ) )
-        /* UTF-8 */
-        from_locale.hd = to_locale.hd = (vlc_iconv_t)(-1);
-    else
-    {
-        /* not UTF-8 */
-        char psz_buf[strlen( psz_charset ) + sizeof( "//translit" )];
-        const char *psz_conv;
-
-        /*
-         * Still allow non-ASCII characters when the locale is not set.
-         * Western Europeans are being favored for historical reasons.
-         */
-        if( strcmp( psz_charset, "ASCII" ) )
-        {
-            sprintf( psz_buf, "%s//translit", psz_charset );
-            psz_conv = psz_buf;
-        }
-        else
-            psz_conv = "ISO-8859-1//translit";
-
-        vlc_mutex_init( p_this, &from_locale.lock );
-        vlc_mutex_init( p_this, &to_locale.lock );
-        from_locale.hd = vlc_iconv_open( "UTF-8", psz_conv );
-        to_locale.hd = vlc_iconv_open( psz_conv, "UTF-8" );
-    }
-
-    free( psz_charset );
-
-    assert( (from_locale.hd == (vlc_iconv_t)(-1))
-            == (to_locale.hd == (vlc_iconv_t)(-1)) );
-
-#elif defined (USE_MB2MB)
-    to_locale.toCP = from_locale.fromCP = CP_ACP;
-    from_locale.toCP = to_locale.fromCP = CP_UTF8;
-#else
-    (void)p_this;
-#endif
+    free (psz_charset);
 }
 
-void LocaleDeinit( void )
+static int find_charset (void)
 {
-#ifdef USE_ICONV
-    if( to_locale.hd != (vlc_iconv_t)(-1) )
-    {
-        vlc_iconv_close( to_locale.hd );
-        vlc_mutex_destroy( &to_locale.lock );
-    }
-
-    if( from_locale.hd != (vlc_iconv_t)(-1) )
-    {
-        vlc_iconv_close( from_locale.hd );
-        vlc_mutex_destroy( &from_locale.lock );
-    }
-#endif
+    static pthread_once_t once = PTHREAD_ONCE_INIT;
+    pthread_once (&once, find_charset_once);
+    return strcmp (charset, "UTF-8");
 }
+#endif
+
 
-static char *locale_fast (const char *string, locale_data_t *p)
+static char *locale_fast (const char *string, vlc_bool_t from)
 {
 #if defined (USE_ICONV)
-    vlc_iconv_t hd = p->hd;
+    if (find_charset ())
+        return (char *)string;
 
+    vlc_iconv_t hd = vlc_iconv_open (from ? "UTF-8" : charset,
+                                     from ? charset : "UTF-8");
     if (hd == (vlc_iconv_t)(-1))
-        return (char *)string;
+        return strdup (string); /* Uho! */
 
     const char *iptr = string;
     size_t inb = strlen (string);
@@ -164,9 +115,6 @@ static char *locale_fast (const char *string, locale_data_t *p)
     if (string == NULL)
         return NULL;
 
-    vlc_mutex_lock (&p->lock);
-    vlc_iconv (hd, NULL, NULL, NULL, NULL);
-
     while (vlc_iconv (hd, &iptr, &inb, &optr, &outb) == (size_t)(-1))
     {
         *optr++ = '?';
@@ -175,8 +123,8 @@ static char *locale_fast (const char *string, locale_data_t *p)
         inb--;
         vlc_iconv (hd, NULL, NULL, NULL, NULL);
     }
-    vlc_mutex_unlock (&p->lock);
     *optr = '\0';
+    vlc_iconv_close (hd);
 
     assert (inb == 0);
     assert (*iptr == '\0');
@@ -190,10 +138,11 @@ static char *locale_fast (const char *string, locale_data_t *p)
     if (string == NULL)
         return NULL;
 
-    len = 1 + MultiByteToWideChar (p->fromCP, 0, string, -1, NULL, 0);
+    len = 1 + MultiByteToWideChar (from ? CP_ACP : CP_UTF8,
+                                   0, string, -1, NULL, 0);
     wchar_t wide[len];
 
-    MultiByteToWideChar (p->fromCP, 0, string, -1, wide, len);
+    MultiByteToWideChar (from ? CP_UTF8 : CP_ACP, 0, string, -1, wide, len);
     len = 1 + WideCharToMultiByte (p->toCP, 0, wide, -1, NULL, 0, NULL, NULL);
     out = malloc (len);
     if (out == NULL)
@@ -207,14 +156,14 @@ static char *locale_fast (const char *string, locale_data_t *p)
 }
 
 
-static inline char *locale_dup (const char *string, locale_data_t *p)
+static inline char *locale_dup (const char *string, vlc_bool_t from)
 {
 #if defined (USE_ICONV)
-    return (p->hd == (vlc_iconv_t)(-1))
-            ? strdup (string)
-            : locale_fast (string, p);
+    if (find_charset ())
+        return strdup (string);
+    return locale_fast (string, from);
 #elif defined (USE_MB2MB)
-    return locale_fast (string, p);
+    return locale_fast (string, from);
 #else
     return strdup (string);
 #endif
@@ -224,10 +173,7 @@ static inline char *locale_dup (const char *string, locale_data_t *p)
 void LocaleFree (const char *str)
 {
 #if defined (USE_ICONV)
-    assert ((to_locale.hd == (vlc_iconv_t)(-1))
-         == (from_locale.hd == (vlc_iconv_t)(-1)));
-
-    if( to_locale.hd != (vlc_iconv_t)(-1) )
+    if (strcmp (charset, "UTF-8"))
         free ((char *)str);
 #elif defined (USE_MB2MB)
     free ((char *)str);
@@ -246,12 +192,12 @@ void LocaleFree (const char *str)
  */
 char *FromLocale (const char *locale)
 {
-    return locale_fast (locale, &from_locale);
+    return locale_fast (locale, VLC_TRUE);
 }
 
 char *FromLocaleDup (const char *locale)
 {
-    return locale_dup (locale, &from_locale);
+    return locale_dup (locale, VLC_TRUE);
 }
 
 
@@ -266,13 +212,13 @@ char *FromLocaleDup (const char *locale)
  */
 char *ToLocale (const char *utf8)
 {
-    return locale_fast (utf8, &to_locale);
+    return locale_fast (utf8, VLC_FALSE);
 }
 
 
 static char *ToLocaleDup (const char *utf8)
 {
-    return locale_dup (utf8, &to_locale);
+    return locale_dup (utf8, VLC_FALSE);
 }