]> git.sesse.net Git - vlc/blob - src/text/wincp.c
Reimplement Win32 GetACP() using gettext.
[vlc] / src / text / wincp.c
1 /*****************************************************************************
2  * wincp.c: Guessing "local" ANSI code page on Microsoft Windows®
3  *****************************************************************************
4  *
5  * Copyright © 2006-2007 Rémi Denis-Courmont
6  * $Id$
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 /*** We need your help to complete this file!! Look for FIXME ***/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <vlc_common.h>
30
31 #ifndef WIN32
32 # include <locale.h>
33 #else
34 # include <windows.h>
35 #endif
36
37 #ifdef __APPLE__
38 #   include <string.h>
39 #endif
40
41 #include <vlc_charset.h>
42
43
44 #ifndef WIN32 /* should work on Win32, but useless */
45 static inline int locale_match (const char *tab, const char *locale)
46 {
47     for (;*tab; tab += 2)
48         if (memcmp (tab, locale, 2) == 0)
49             return 0;
50     return 1;
51 }
52
53
54 /**
55  * @return a fallback characters encoding to be used, given a locale.
56  */
57 static const char *FindFallbackEncoding (const char *locale)
58 {
59     if ((locale == NULL) || (strlen (locale) < 2)
60      || !strcasecmp (locale, "POSIX"))
61         return "CP1252"; /* Yeah, this is totally western-biased */
62
63
64     /*** The ISO-8859 series (anything but Asia) ***/
65     // Latin-1 Western-European languages (ISO-8859-1)
66     static const char western[] =
67         "aa" "af" "an" "br" "ca" "da" "de" "en" "es" "et" "eu" "fi" "fo" "fr"
68         "ga" "gd" "gl" "gv" "id" "is" "it" "kl" "kw" "mg" "ms" "nb" "nl" "nn"
69         "no" "oc" "om" "pt" "so" "sq" "st" "sv" "tl" "uz" "wa" "xh" "zu"
70         "eo" "mt" "cy";
71     if (!locale_match (western, locale))
72         return "CP1252"; // Compatible Microsoft superset
73
74     // Latin-2 Slavic languages (ISO-8859-2)
75     static const char slavic[] = "bs" "cs" "hr" "hu" "pl" "ro" "sk" "sl";
76     if (!locale_match (slavic, locale))
77         return "CP1250"; // CP1250 is more common, but incompatible
78
79     // Latin-3 Southern European languages (ISO-8859-3)
80     // "eo" and "mt" -> Latin-1 instead, I presume(?).
81     // "tr" -> ISO-8859-9 instead
82
83     // Latin-4 North-European languages (ISO-8859-4)
84     // -> Latin-1 instead
85
86     /* Cyrillic alphabet languages (ISO-8859-5) */
87     static const char cyrillic[] = "be" "bg" "mk" "ru" "sr" "mn";
88     // FIXME: cyrillic only true for mn in Mongolia
89     if (!locale_match (cyrillic, locale))
90         return "CP1251"; // KOI8, ISO-8859-5 and CP1251 are incompatible(?)
91
92     /* Arabic (ISO-8859-6) */
93     static const char arabic[] = "ar" "fa";
94     if (!locale_match (arabic, locale))
95         // FIXME: someone check if we should return CP1256 or ISO-8859-6
96         return "CP1256"; // CP1256 is(?) more common, but incompatible(?)
97
98     /* Greek (ISO-8859-7) */
99     if (!locale_match ("el", locale))
100         // FIXME: someone check if we should return CP1253 or ISO-8859-7
101         return "CP1253"; // CP1253 is(?) more common and less incompatible
102
103     /* Hebrew (ISO-8859-8) */
104     if (!locale_match ("he" "iw" "yi", locale))
105         return "ISO-8859-8"; // CP1255 is reportedly screwed up
106
107     /* Latin-5 Turkish (ISO-8859-9) */
108     if (!locale_match ("tr" "ku", locale))
109         return "CP1254"; // Compatible Microsoft superset
110
111     /* Latin-6 “North-European” languages (ISO-8859-10) */
112     /* It is so much north European that glibc only uses that for Luganda
113      * which is spoken in Uganda... unless someone complains, I'm not
114      * using this one; let's fallback to CP1252 here. */
115
116     // ISO-8859-11 does arguably not exist. Thai is handled below.
117
118     // ISO-8859-12 really doesn't exist.
119
120     // Latin-7 Baltic languages (ISO-8859-13)
121     if (!locale_match ("lt" "lv" "mi", locale))
122         // FIXME: mi = New Zealand, doesn't sound baltic!
123         return "CP1257"; // Compatible Microsoft superset
124
125     // Latin-8 Celtic languages (ISO-8859-14)
126     // "cy" -> use Latin-1 instead (most likely English or French)
127
128     // Latin-9 (ISO-8859-15) -> see Latin-1
129
130     // Latin-10 (ISO-8859-16) does not seem to be used
131
132     /*** KOI series ***/
133     // For Russian, we use CP1251
134     if (!locale_match ("uk", locale))
135         return "KOI8-U";
136
137     if (!locale_match ("tg", locale))
138         return "KOI8-T";
139
140     /*** Asia ***/
141     // Japanese
142     if (!locale_match ("jp", locale))
143         return "SHIFT-JIS"; // Shift-JIS is way more common than EUC-JP
144
145     // Korean
146     if (!locale_match ("ko", locale))
147         return "CP949"; // Microsoft non-standard superset of EUC-KR
148
149     // Thai
150     static const char thai[] = "th" "km" "lo";
151     //FIXME: afaik, khmer and lao are/were not in windows and are close to tahi
152     if (!locale_match (thai, locale))
153         return "TIS-620";
154
155     // Vietnamese (FIXME: more infos needed)
156     if (!locale_match ("vt", locale))
157         /* VISCII is probably a bad idea as it is not extended ASCII */
158         /* glibc has TCVN5712-1 */
159         return "CP1258";
160
161     /* Kazakh (FIXME: more infos needed) */
162     if (!locale_match ("kk", locale))
163         return "PT154";
164
165     // Chinese. The politically incompatible character sets.
166     if (!locale_match ("zh", locale))
167     {
168         if ((strlen (locale) >= 5) && (locale[2] != '_'))
169             locale += 3;
170
171         // Hong Kong
172         if (!locale_match ("HK", locale))
173             return "BIG5-HKSCS"; /* FIXME: use something else? */
174
175         // Taiwan island
176         if (!locale_match ("TW", locale))
177             return "BIG5";
178
179         // People's Republic of China and Singapore
180         /*
181          * GB18030 can represent any Unicode code point
182          * (like UTF-8), while remaining compatible with GBK
183          * FIXME: is it compatible with GB2312? if not, should we
184          * use GB2312 instead?
185          */
186         return "GB18030";
187     }
188
189     return "ASCII";
190 }
191 #endif
192
193 /**
194  * GetFallbackEncoding() suggests an encoding to be used for non UTF-8
195  * text files accord to the system's local settings. It is only a best
196  * guess.
197  */
198 const char *GetFallbackEncoding( void )
199 {
200 #ifndef WIN32
201     const char *psz_lang;
202
203     psz_lang = getenv ("LC_ALL");
204     if ((psz_lang == NULL) || !*psz_lang)
205     {
206         psz_lang = getenv ("LC_CTYPE");
207         if ((psz_lang == NULL) || !*psz_lang)
208             psz_lang = getenv ("LANG");
209     }
210
211     return FindFallbackEncoding (psz_lang);
212 #else
213     static char buf[16] = "";
214     static vlc_mutex_t lock = VLC_STATIC_MUTEX;
215
216     vlc_mutex_lock (&lock);
217     if (buf[0] == 0)
218     {
219         int cp = GetACP ();
220
221         switch (cp)
222         {
223             case 1255: // Hebrew, CP1255 screws up somewhat
224                 strcpy (buf, "ISO-8859-8");
225                 break;
226             default:
227                 snprintf (buf, sizeof (buf), "CP%u", cp);
228         }
229     }
230     vlc_mutex_unlock (&lock);
231     return buf;
232 #endif
233 }