| 1 | /* |
| 2 | Copyright (C) 2002-2004 MySQL AB |
| 3 | |
| 4 | This program is free software; you can redistribute it and/or modify |
| 5 | it under the terms of version 2 of the GNU General Public License as |
| 6 | published by the Free Software Foundation. |
| 7 | |
| 8 | There are special exceptions to the terms and conditions of the GPL |
| 9 | as it is applied to this software. View the full text of the |
| 10 | exception in file EXCEPTIONS-CONNECTOR-J in the directory of this |
| 11 | software distribution. |
| 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 General Public License |
| 19 | along with this program; if not, write to the Free Software |
| 20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 21 | |
| 22 | |
| 23 | |
| 24 | */ |
| 25 | package com.mysql.jdbc; |
| 26 | |
| 27 | import java.sql.SQLException; |
| 28 | import java.util.ArrayList; |
| 29 | import java.util.Collections; |
| 30 | import java.util.HashMap; |
| 31 | import java.util.Iterator; |
| 32 | import java.util.List; |
| 33 | import java.util.Locale; |
| 34 | import java.util.Map; |
| 35 | import java.util.Properties; |
| 36 | import java.util.Set; |
| 37 | import java.util.SortedSet; |
| 38 | |
| 39 | /** |
| 40 | * Mapping between MySQL charset names and Java charset names. I've investigated |
| 41 | * placing these in a .properties file, but unfortunately under most appservers |
| 42 | * this complicates configuration because the security policy needs to be |
| 43 | * changed by the user to allow the driver to read them :( |
| 44 | * |
| 45 | * @author Mark Matthews |
| 46 | */ |
| 47 | public class CharsetMapping { |
| 48 | private static final Properties CHARSET_CONFIG = new Properties(); |
| 49 | |
| 50 | /** |
| 51 | * Map of MySQL-4.1 charset indexes to Java encoding names |
| 52 | */ |
| 53 | public static final String[] INDEX_TO_CHARSET; |
| 54 | |
| 55 | /** Mapping of Java charset names to MySQL charset names */ |
| 56 | private static final Map JAVA_TO_MYSQL_CHARSET_MAP; |
| 57 | |
| 58 | private static final Map JAVA_UC_TO_MYSQL_CHARSET_MAP; |
| 59 | |
| 60 | private static final Map ERROR_MESSAGE_FILE_TO_MYSQL_CHARSET_MAP; |
| 61 | |
| 62 | /** Map/List of multibyte character sets (using MySQL names) */ |
| 63 | private static final Map MULTIBYTE_CHARSETS; |
| 64 | |
| 65 | private static final Map MYSQL_TO_JAVA_CHARSET_MAP; |
| 66 | |
| 67 | static { |
| 68 | |
| 69 | CHARSET_CONFIG.setProperty("javaToMysqlMappings", |
| 70 | // |
| 71 | // Note: This used to be stored in Charsets.properties, |
| 72 | // but turned out to be problematic when dealing with |
| 73 | // Tomcat classloaders when the security manager was |
| 74 | // enabled |
| 75 | // |
| 76 | // Java Encoding MySQL Name (and version, '*' |
| 77 | // denotes preferred value) |
| 78 | // |
| 79 | "US-ASCII = usa7," |
| 80 | + "US-ASCII = ascii," |
| 81 | + "Big5 = big5," |
| 82 | + "GBK = gbk," |
| 83 | + "SJIS = sjis," |
| 84 | + "EUC_CN = gb2312," |
| 85 | + "EUC_JP = ujis," |
| 86 | + "EUC_JP_Solaris = >5.0.3 eucjpms," |
| 87 | + "EUC_KR = euc_kr," |
| 88 | + "EUC_KR = >4.1.0 euckr," |
| 89 | + "ISO8859_1 = *latin1," |
| 90 | + "ISO8859_1 = latin1_de," |
| 91 | + "ISO8859_1 = german1," |
| 92 | + "ISO8859_1 = danish," |
| 93 | + "ISO8859_2 = latin2," |
| 94 | + "ISO8859_2 = czech," |
| 95 | + "ISO8859_2 = hungarian," |
| 96 | + "ISO8859_2 = croat," |
| 97 | + "ISO8859_7 = greek," |
| 98 | + "ISO8859_7 = latin7," |
| 99 | + "ISO8859_8 = hebrew," |
| 100 | + "ISO8859_9 = latin5," |
| 101 | + "ISO8859_13 = latvian," |
| 102 | + "ISO8859_13 = latvian1," |
| 103 | + "ISO8859_13 = estonia," |
| 104 | + "Cp437 = *>4.1.0 cp850," |
| 105 | + "Cp437 = dos," |
| 106 | + "Cp850 = Cp850," |
| 107 | + "Cp852 = Cp852," |
| 108 | + "Cp866 = cp866," |
| 109 | + "KOI8_R = koi8_ru," |
| 110 | + "KOI8_R = >4.1.0 koi8r," |
| 111 | + "TIS620 = tis620," |
| 112 | + "Cp1250 = cp1250," |
| 113 | + "Cp1250 = win1250," |
| 114 | + "Cp1251 = *>4.1.0 cp1251," |
| 115 | + "Cp1251 = win1251," |
| 116 | + "Cp1251 = cp1251cias," |
| 117 | + "Cp1251 = cp1251csas," |
| 118 | + "Cp1256 = cp1256," |
| 119 | + "Cp1251 = win1251ukr," |
| 120 | + "Cp1252 = latin1," |
| 121 | + "Cp1257 = cp1257," |
| 122 | + "MacRoman = macroman," |
| 123 | + "MacCentralEurope = macce," |
| 124 | + "UTF-8 = utf8," |
| 125 | + "UnicodeBig = ucs2," |
| 126 | + "US-ASCII = binary," |
| 127 | + "Cp943 = sjis," |
| 128 | + "MS932 = sjis," |
| 129 | + "MS932 = >4.1.11 cp932," |
| 130 | + "WINDOWS-31J = sjis," |
| 131 | + "WINDOWS-31J = >4.1.11 cp932," |
| 132 | + "CP932 = sjis," |
| 133 | + "CP932 = *>4.1.11 cp932," |
| 134 | + "SHIFT_JIS = sjis," |
| 135 | + "ASCII = ascii," |
| 136 | + "LATIN5 = latin5," |
| 137 | + "LATIN7 = latin7," |
| 138 | + "HEBREW = hebrew," |
| 139 | + "GREEK = greek," |
| 140 | + "EUCKR = euckr," |
| 141 | + "GB2312 = gb2312," |
| 142 | + "LATIN2 = latin2"); |
| 143 | |
| 144 | HashMap javaToMysqlMap = new HashMap(); |
| 145 | |
| 146 | populateMapWithKeyValuePairs("javaToMysqlMappings", javaToMysqlMap, |
| 147 | true, false); |
| 148 | JAVA_TO_MYSQL_CHARSET_MAP = Collections.unmodifiableMap(javaToMysqlMap); |
| 149 | |
| 150 | HashMap mysqlToJavaMap = new HashMap(); |
| 151 | |
| 152 | Set keySet = JAVA_TO_MYSQL_CHARSET_MAP.keySet(); |
| 153 | |
| 154 | Iterator javaCharsets = keySet.iterator(); |
| 155 | |
| 156 | while (javaCharsets.hasNext()) { |
| 157 | Object javaEncodingName = javaCharsets.next(); |
| 158 | List mysqlEncodingList = (List) JAVA_TO_MYSQL_CHARSET_MAP |
| 159 | .get(javaEncodingName); |
| 160 | |
| 161 | Iterator mysqlEncodings = mysqlEncodingList.iterator(); |
| 162 | |
| 163 | String mysqlEncodingName = null; |
| 164 | |
| 165 | while (mysqlEncodings.hasNext()) { |
| 166 | VersionedStringProperty mysqlProp = (VersionedStringProperty) mysqlEncodings |
| 167 | .next(); |
| 168 | mysqlEncodingName = mysqlProp.toString(); |
| 169 | |
| 170 | mysqlToJavaMap.put(mysqlEncodingName, javaEncodingName); |
| 171 | mysqlToJavaMap.put(mysqlEncodingName |
| 172 | .toUpperCase(Locale.ENGLISH), javaEncodingName); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | // we don't want CP932 to map to CP932 |
| 177 | mysqlToJavaMap.put("cp932", "Windows-31J"); |
| 178 | mysqlToJavaMap.put("CP932", "Windows-31J"); |
| 179 | |
| 180 | MYSQL_TO_JAVA_CHARSET_MAP = Collections.unmodifiableMap(mysqlToJavaMap); |
| 181 | |
| 182 | HashMap ucMap = new HashMap(JAVA_TO_MYSQL_CHARSET_MAP.size()); |
| 183 | |
| 184 | Iterator javaNamesKeys = JAVA_TO_MYSQL_CHARSET_MAP.keySet().iterator(); |
| 185 | |
| 186 | while (javaNamesKeys.hasNext()) { |
| 187 | String key = (String) javaNamesKeys.next(); |
| 188 | |
| 189 | ucMap.put(key.toUpperCase(Locale.ENGLISH), |
| 190 | JAVA_TO_MYSQL_CHARSET_MAP.get(key)); |
| 191 | } |
| 192 | |
| 193 | JAVA_UC_TO_MYSQL_CHARSET_MAP = Collections.unmodifiableMap(ucMap); |
| 194 | |
| 195 | // |
| 196 | // Character sets that we can't convert |
| 197 | // ourselves. |
| 198 | // |
| 199 | HashMap tempMapMulti = new HashMap(); |
| 200 | |
| 201 | CHARSET_CONFIG.setProperty("multibyteCharsets", |
| 202 | // |
| 203 | // Note: This used to be stored in Charsets.properties, |
| 204 | // but turned out to be problematic when dealing with |
| 205 | // Tomcat classloaders when the security manager was |
| 206 | // enabled |
| 207 | // |
| 208 | // Java Name MySQL Name (not currently used) |
| 209 | // |
| 210 | |
| 211 | "Big5 = big5," |
| 212 | + "GBK = gbk," |
| 213 | + "SJIS = sjis," |
| 214 | + "EUC_CN = gb2312," |
| 215 | + "EUC_JP = ujis," |
| 216 | + "EUC_JP_Solaris = eucjpms," |
| 217 | + "EUC_KR = euc_kr," |
| 218 | + "EUC_KR = >4.1.0 euckr," |
| 219 | + "Cp943 = sjis," |
| 220 | + "Cp943 = cp943," |
| 221 | + "WINDOWS-31J = sjis," |
| 222 | + "WINDOWS-31J = cp932," |
| 223 | + "CP932 = cp932," |
| 224 | + "MS932 = sjis," |
| 225 | + "MS932 = cp932," |
| 226 | + "SHIFT_JIS = sjis," |
| 227 | + "EUCKR = euckr," |
| 228 | + "GB2312 = gb2312," |
| 229 | + "UTF-8 = utf8," |
| 230 | + "utf8 = utf8," |
| 231 | + "UnicodeBig = ucs2"); |
| 232 | |
| 233 | populateMapWithKeyValuePairs("multibyteCharsets", tempMapMulti, false, |
| 234 | true); |
| 235 | |
| 236 | MULTIBYTE_CHARSETS = Collections.unmodifiableMap(tempMapMulti); |
| 237 | |
| 238 | INDEX_TO_CHARSET = new String[99]; |
| 239 | |
| 240 | try { |
| 241 | INDEX_TO_CHARSET[1] = getJavaEncodingForMysqlEncoding("big5", null); |
| 242 | INDEX_TO_CHARSET[2] = getJavaEncodingForMysqlEncoding("czech", null); |
| 243 | INDEX_TO_CHARSET[3] = getJavaEncodingForMysqlEncoding("dec8", null); |
| 244 | INDEX_TO_CHARSET[4] = getJavaEncodingForMysqlEncoding("dos", null); |
| 245 | INDEX_TO_CHARSET[5] = getJavaEncodingForMysqlEncoding("german1", |
| 246 | null); |
| 247 | INDEX_TO_CHARSET[6] = getJavaEncodingForMysqlEncoding("hp8", null); |
| 248 | INDEX_TO_CHARSET[7] = getJavaEncodingForMysqlEncoding("koi8_ru", |
| 249 | null); |
| 250 | INDEX_TO_CHARSET[8] = getJavaEncodingForMysqlEncoding("latin1", |
| 251 | null); |
| 252 | INDEX_TO_CHARSET[9] = getJavaEncodingForMysqlEncoding("latin2", |
| 253 | null); |
| 254 | INDEX_TO_CHARSET[10] = getJavaEncodingForMysqlEncoding("swe7", null); |
| 255 | INDEX_TO_CHARSET[11] = getJavaEncodingForMysqlEncoding("usa7", null); |
| 256 | INDEX_TO_CHARSET[12] = getJavaEncodingForMysqlEncoding("ujis", null); |
| 257 | INDEX_TO_CHARSET[13] = getJavaEncodingForMysqlEncoding("sjis", null); |
| 258 | INDEX_TO_CHARSET[14] = getJavaEncodingForMysqlEncoding("cp1251", |
| 259 | null); |
| 260 | INDEX_TO_CHARSET[15] = getJavaEncodingForMysqlEncoding("danish", |
| 261 | null); |
| 262 | INDEX_TO_CHARSET[16] = getJavaEncodingForMysqlEncoding("hebrew", |
| 263 | null); |
| 264 | INDEX_TO_CHARSET[18] = getJavaEncodingForMysqlEncoding("tis620", |
| 265 | null); |
| 266 | INDEX_TO_CHARSET[19] = getJavaEncodingForMysqlEncoding("euc_kr", |
| 267 | null); |
| 268 | INDEX_TO_CHARSET[20] = getJavaEncodingForMysqlEncoding("estonia", |
| 269 | null); |
| 270 | INDEX_TO_CHARSET[21] = getJavaEncodingForMysqlEncoding("hungarian", |
| 271 | null); |
| 272 | INDEX_TO_CHARSET[22] = getJavaEncodingForMysqlEncoding("koi8_ukr", |
| 273 | null); |
| 274 | INDEX_TO_CHARSET[23] = getJavaEncodingForMysqlEncoding( |
| 275 | "win1251ukr", null); |
| 276 | INDEX_TO_CHARSET[24] = getJavaEncodingForMysqlEncoding("gb2312", |
| 277 | null); |
| 278 | INDEX_TO_CHARSET[25] = getJavaEncodingForMysqlEncoding("greek", |
| 279 | null); |
| 280 | INDEX_TO_CHARSET[26] = getJavaEncodingForMysqlEncoding("win1250", |
| 281 | null); |
| 282 | INDEX_TO_CHARSET[27] = getJavaEncodingForMysqlEncoding("croat", |
| 283 | null); |
| 284 | INDEX_TO_CHARSET[28] = getJavaEncodingForMysqlEncoding("gbk", null); |
| 285 | INDEX_TO_CHARSET[29] = getJavaEncodingForMysqlEncoding("cp1257", |
| 286 | null); |
| 287 | INDEX_TO_CHARSET[30] = getJavaEncodingForMysqlEncoding("latin5", |
| 288 | null); |
| 289 | INDEX_TO_CHARSET[31] = getJavaEncodingForMysqlEncoding("latin1_de", |
| 290 | null); |
| 291 | INDEX_TO_CHARSET[32] = getJavaEncodingForMysqlEncoding("armscii8", |
| 292 | null); |
| 293 | INDEX_TO_CHARSET[33] = getJavaEncodingForMysqlEncoding("utf8", null); |
| 294 | INDEX_TO_CHARSET[34] = getJavaEncodingForMysqlEncoding("win1250ch", |
| 295 | null); |
| 296 | INDEX_TO_CHARSET[35] = getJavaEncodingForMysqlEncoding("ucs2", null); |
| 297 | INDEX_TO_CHARSET[36] = getJavaEncodingForMysqlEncoding("cp866", |
| 298 | null); |
| 299 | INDEX_TO_CHARSET[37] = getJavaEncodingForMysqlEncoding("keybcs2", |
| 300 | null); |
| 301 | INDEX_TO_CHARSET[38] = getJavaEncodingForMysqlEncoding("macce", |
| 302 | null); |
| 303 | INDEX_TO_CHARSET[39] = getJavaEncodingForMysqlEncoding("macroman", |
| 304 | null); |
| 305 | INDEX_TO_CHARSET[40] = getJavaEncodingForMysqlEncoding("pclatin2", |
| 306 | null); |
| 307 | INDEX_TO_CHARSET[41] = getJavaEncodingForMysqlEncoding("latvian", |
| 308 | null); |
| 309 | INDEX_TO_CHARSET[42] = getJavaEncodingForMysqlEncoding("latvian1", |
| 310 | null); |
| 311 | INDEX_TO_CHARSET[43] = getJavaEncodingForMysqlEncoding("maccebin", |
| 312 | null); |
| 313 | INDEX_TO_CHARSET[44] = getJavaEncodingForMysqlEncoding("macceciai", |
| 314 | null); |
| 315 | INDEX_TO_CHARSET[45] = getJavaEncodingForMysqlEncoding("maccecias", |
| 316 | null); |
| 317 | INDEX_TO_CHARSET[46] = getJavaEncodingForMysqlEncoding("maccecsas", |
| 318 | null); |
| 319 | INDEX_TO_CHARSET[47] = getJavaEncodingForMysqlEncoding("latin1bin", |
| 320 | null); |
| 321 | INDEX_TO_CHARSET[48] = getJavaEncodingForMysqlEncoding( |
| 322 | "latin1cias", null); |
| 323 | INDEX_TO_CHARSET[49] = getJavaEncodingForMysqlEncoding( |
| 324 | "latin1csas", null); |
| 325 | INDEX_TO_CHARSET[50] = getJavaEncodingForMysqlEncoding("cp1251bin", |
| 326 | null); |
| 327 | INDEX_TO_CHARSET[51] = getJavaEncodingForMysqlEncoding( |
| 328 | "cp1251cias", null); |
| 329 | INDEX_TO_CHARSET[52] = getJavaEncodingForMysqlEncoding( |
| 330 | "cp1251csas", null); |
| 331 | INDEX_TO_CHARSET[53] = getJavaEncodingForMysqlEncoding( |
| 332 | "macromanbin", null); |
| 333 | INDEX_TO_CHARSET[54] = getJavaEncodingForMysqlEncoding( |
| 334 | "macromancias", null); |
| 335 | INDEX_TO_CHARSET[55] = getJavaEncodingForMysqlEncoding( |
| 336 | "macromanciai", null); |
| 337 | INDEX_TO_CHARSET[56] = getJavaEncodingForMysqlEncoding( |
| 338 | "macromancsas", null); |
| 339 | INDEX_TO_CHARSET[57] = getJavaEncodingForMysqlEncoding("cp1256", |
| 340 | null); |
| 341 | INDEX_TO_CHARSET[63] = getJavaEncodingForMysqlEncoding("binary", |
| 342 | null); |
| 343 | INDEX_TO_CHARSET[64] = getJavaEncodingForMysqlEncoding("armscii", |
| 344 | null); |
| 345 | INDEX_TO_CHARSET[65] = getJavaEncodingForMysqlEncoding("ascii", |
| 346 | null); |
| 347 | INDEX_TO_CHARSET[66] = getJavaEncodingForMysqlEncoding("cp1250", |
| 348 | null); |
| 349 | INDEX_TO_CHARSET[67] = getJavaEncodingForMysqlEncoding("cp1256", |
| 350 | null); |
| 351 | INDEX_TO_CHARSET[68] = getJavaEncodingForMysqlEncoding("cp866", |
| 352 | null); |
| 353 | INDEX_TO_CHARSET[69] = getJavaEncodingForMysqlEncoding("dec8", null); |
| 354 | INDEX_TO_CHARSET[70] = getJavaEncodingForMysqlEncoding("greek", |
| 355 | null); |
| 356 | INDEX_TO_CHARSET[71] = getJavaEncodingForMysqlEncoding("hebrew", |
| 357 | null); |
| 358 | INDEX_TO_CHARSET[72] = getJavaEncodingForMysqlEncoding("hp8", null); |
| 359 | INDEX_TO_CHARSET[73] = getJavaEncodingForMysqlEncoding("keybcs2", |
| 360 | null); |
| 361 | INDEX_TO_CHARSET[74] = getJavaEncodingForMysqlEncoding("koi8r", |
| 362 | null); |
| 363 | INDEX_TO_CHARSET[75] = getJavaEncodingForMysqlEncoding("koi8ukr", |
| 364 | null); |
| 365 | INDEX_TO_CHARSET[77] = getJavaEncodingForMysqlEncoding("latin2", |
| 366 | null); |
| 367 | INDEX_TO_CHARSET[78] = getJavaEncodingForMysqlEncoding("latin5", |
| 368 | null); |
| 369 | INDEX_TO_CHARSET[79] = getJavaEncodingForMysqlEncoding("latin7", |
| 370 | null); |
| 371 | INDEX_TO_CHARSET[80] = getJavaEncodingForMysqlEncoding("cp850", |
| 372 | null); |
| 373 | INDEX_TO_CHARSET[81] = getJavaEncodingForMysqlEncoding("cp852", |
| 374 | null); |
| 375 | INDEX_TO_CHARSET[82] = getJavaEncodingForMysqlEncoding("swe7", null); |
| 376 | INDEX_TO_CHARSET[83] = getJavaEncodingForMysqlEncoding("utf8", null); |
| 377 | INDEX_TO_CHARSET[84] = getJavaEncodingForMysqlEncoding("big5", null); |
| 378 | INDEX_TO_CHARSET[85] = getJavaEncodingForMysqlEncoding("euckr", |
| 379 | null); |
| 380 | INDEX_TO_CHARSET[86] = getJavaEncodingForMysqlEncoding("gb2312", |
| 381 | null); |
| 382 | INDEX_TO_CHARSET[87] = getJavaEncodingForMysqlEncoding("gbk", null); |
| 383 | INDEX_TO_CHARSET[88] = getJavaEncodingForMysqlEncoding("sjis", null); |
| 384 | INDEX_TO_CHARSET[89] = getJavaEncodingForMysqlEncoding("tis620", |
| 385 | null); |
| 386 | INDEX_TO_CHARSET[90] = getJavaEncodingForMysqlEncoding("ucs2", null); |
| 387 | INDEX_TO_CHARSET[91] = getJavaEncodingForMysqlEncoding("ujis", null); |
| 388 | INDEX_TO_CHARSET[92] = getJavaEncodingForMysqlEncoding("geostd8", |
| 389 | null); |
| 390 | INDEX_TO_CHARSET[93] = getJavaEncodingForMysqlEncoding("geostd8", |
| 391 | null); |
| 392 | INDEX_TO_CHARSET[94] = getJavaEncodingForMysqlEncoding("latin1", |
| 393 | null); |
| 394 | INDEX_TO_CHARSET[95] = getJavaEncodingForMysqlEncoding("cp932", |
| 395 | null); |
| 396 | INDEX_TO_CHARSET[96] = getJavaEncodingForMysqlEncoding("cp932", |
| 397 | null); |
| 398 | INDEX_TO_CHARSET[97] = getJavaEncodingForMysqlEncoding("eucjpms", |
| 399 | null); |
| 400 | INDEX_TO_CHARSET[98] = getJavaEncodingForMysqlEncoding("eucjpms", |
| 401 | null); |
| 402 | } catch (SQLException sqlEx) { |
| 403 | // ignore, it won't happen in this case |
| 404 | } |
| 405 | |
| 406 | Map tempMap = new HashMap(); |
| 407 | |
| 408 | tempMap.put("czech", "latin2"); |
| 409 | tempMap.put("danish", "latin1"); |
| 410 | tempMap.put("dutch", "latin1"); |
| 411 | tempMap.put("english", "latin1"); |
| 412 | tempMap.put("estonian", "latin7"); |
| 413 | tempMap.put("french", "latin1"); |
| 414 | tempMap.put("german", "latin1"); |
| 415 | tempMap.put("greek", "greek"); |
| 416 | tempMap.put("hungarian", "latin2"); |
| 417 | tempMap.put("italian", "latin1"); |
| 418 | tempMap.put("japanese", "ujis"); |
| 419 | tempMap.put("japanese-sjis", "sjis"); |
| 420 | tempMap.put("korean", "euckr"); |
| 421 | tempMap.put("norwegian", "latin1"); |
| 422 | tempMap.put("norwegian-ny", "latin1"); |
| 423 | tempMap.put("polish", "latin2"); |
| 424 | tempMap.put("portuguese", "latin1"); |
| 425 | tempMap.put("romanian", "latin2"); |
| 426 | tempMap.put("russian", "koi8r"); |
| 427 | tempMap.put("serbian", "cp1250"); |
| 428 | tempMap.put("slovak", "latin2"); |
| 429 | tempMap.put("spanish", "latin1"); |
| 430 | tempMap.put("swedish", "latin1"); |
| 431 | tempMap.put("ukrainian", "koi8u"); |
| 432 | |
| 433 | ERROR_MESSAGE_FILE_TO_MYSQL_CHARSET_MAP = |
| 434 | Collections.unmodifiableMap(tempMap); |
| 435 | } |
| 436 | |
| 437 | final static String getJavaEncodingForMysqlEncoding(String mysqlEncoding, |
| 438 | Connection conn) throws SQLException { |
| 439 | |
| 440 | if (conn != null && conn.versionMeetsMinimum(4, 1, 0) && |
| 441 | "latin1".equalsIgnoreCase(mysqlEncoding)) { |
| 442 | return "Cp1252"; |
| 443 | } |
| 444 | |
| 445 | return (String) MYSQL_TO_JAVA_CHARSET_MAP.get(mysqlEncoding); |
| 446 | } |
| 447 | |
| 448 | final static String getMysqlEncodingForJavaEncoding(String javaEncodingUC, |
| 449 | Connection conn) throws SQLException { |
| 450 | List mysqlEncodings = (List) CharsetMapping.JAVA_UC_TO_MYSQL_CHARSET_MAP |
| 451 | .get(javaEncodingUC); |
| 452 | ; |
| 453 | |
| 454 | if (mysqlEncodings != null) { |
| 455 | Iterator iter = mysqlEncodings.iterator(); |
| 456 | |
| 457 | VersionedStringProperty versionedProp = null; |
| 458 | |
| 459 | while (iter.hasNext()) { |
| 460 | VersionedStringProperty propToCheck = (VersionedStringProperty) iter |
| 461 | .next(); |
| 462 | |
| 463 | if (conn == null) { |
| 464 | // Take the first one we get |
| 465 | |
| 466 | return propToCheck.toString(); |
| 467 | } |
| 468 | |
| 469 | if (versionedProp != null && !versionedProp.preferredValue) { |
| 470 | if (versionedProp.majorVersion == propToCheck.majorVersion |
| 471 | && versionedProp.minorVersion == propToCheck.minorVersion |
| 472 | && versionedProp.subminorVersion == propToCheck.subminorVersion) { |
| 473 | return versionedProp.toString(); |
| 474 | } |
| 475 | } |
| 476 | |
| 477 | if (propToCheck.isOkayForVersion(conn)) { |
| 478 | if (propToCheck.preferredValue) { |
| 479 | return propToCheck.toString(); |
| 480 | } |
| 481 | |
| 482 | versionedProp = propToCheck; |
| 483 | } else { |
| 484 | break; |
| 485 | } |
| 486 | } |
| 487 | |
| 488 | if (versionedProp != null) { |
| 489 | return versionedProp.toString(); |
| 490 | } |
| 491 | } |
| 492 | |
| 493 | return null; |
| 494 | } |
| 495 | |
| 496 | final static int getNumberOfCharsetsConfigured() { |
| 497 | return MYSQL_TO_JAVA_CHARSET_MAP.size() / 2; // because we UC every |
| 498 | // key |
| 499 | } |
| 500 | |
| 501 | /** |
| 502 | * Returns the character encoding for error messages returned from the |
| 503 | * server. Doesn't return useful values other than Cp1252 until the driver |
| 504 | * has gone through initialization phase and determined server configuration, |
| 505 | * as not enough information is available to make an intelligent decision |
| 506 | * until then. |
| 507 | * |
| 508 | * @param conn the connection to the MySQL server |
| 509 | * @return the Java encoding name that error messages use |
| 510 | * @throws SQLException if determination of the character encoding fails |
| 511 | */ |
| 512 | final static String getCharacterEncodingForErrorMessages(Connection conn) throws SQLException { |
| 513 | String errorMessageFile = conn.getServerVariable("language"); |
| 514 | |
| 515 | if (errorMessageFile == null || errorMessageFile.length() == 0) { |
| 516 | // punt |
| 517 | return "Cp1252"; |
| 518 | } |
| 519 | |
| 520 | int endWithoutSlash = errorMessageFile.length(); |
| 521 | |
| 522 | if (errorMessageFile.endsWith("/") || errorMessageFile.endsWith("\\")) { |
| 523 | endWithoutSlash--; |
| 524 | } |
| 525 | |
| 526 | int lastSlashIndex = errorMessageFile.lastIndexOf('/', endWithoutSlash - 1); |
| 527 | |
| 528 | if (lastSlashIndex == -1) { |
| 529 | lastSlashIndex = errorMessageFile.lastIndexOf('\\', endWithoutSlash - 1); |
| 530 | } |
| 531 | |
| 532 | if (lastSlashIndex == -1) { |
| 533 | lastSlashIndex = 0; |
| 534 | } |
| 535 | |
| 536 | if (lastSlashIndex == endWithoutSlash || endWithoutSlash < lastSlashIndex) { |
| 537 | // punt |
| 538 | return "Cp1252"; |
| 539 | } |
| 540 | |
| 541 | errorMessageFile = errorMessageFile.substring(lastSlashIndex + 1, endWithoutSlash); |
| 542 | |
| 543 | String errorMessageEncodingMysql = (String)ERROR_MESSAGE_FILE_TO_MYSQL_CHARSET_MAP.get(errorMessageFile); |
| 544 | |
| 545 | if (errorMessageEncodingMysql == null) { |
| 546 | // punt |
| 547 | return "Cp1252"; |
| 548 | } |
| 549 | |
| 550 | String javaEncoding = getJavaEncodingForMysqlEncoding(errorMessageEncodingMysql, conn); |
| 551 | |
| 552 | if (javaEncoding == null) { |
| 553 | // punt |
| 554 | return "Cp1252"; |
| 555 | } |
| 556 | |
| 557 | return javaEncoding; |
| 558 | } |
| 559 | |
| 560 | final static boolean isAliasForSjis(String encoding) { |
| 561 | return ("SJIS".equalsIgnoreCase(encoding) |
| 562 | || "WINDOWS-31J".equalsIgnoreCase(encoding) |
| 563 | || "MS932".equalsIgnoreCase(encoding) |
| 564 | || "SHIFT_JIS".equalsIgnoreCase(encoding) || "CP943" |
| 565 | .equalsIgnoreCase(encoding)); |
| 566 | |
| 567 | } |
| 568 | |
| 569 | final static boolean isMultibyteCharset(String javaEncodingName) { |
| 570 | String javaEncodingNameUC = javaEncodingName |
| 571 | .toUpperCase(Locale.ENGLISH); |
| 572 | |
| 573 | return MULTIBYTE_CHARSETS.containsKey(javaEncodingNameUC); |
| 574 | } |
| 575 | |
| 576 | private static void populateMapWithKeyValuePairs(String configKey, |
| 577 | Map mapToPopulate, boolean addVersionedProperties, |
| 578 | boolean addUppercaseKeys) { |
| 579 | String javaToMysqlConfig = CHARSET_CONFIG.getProperty(configKey); |
| 580 | |
| 581 | if (javaToMysqlConfig != null) { |
| 582 | List mappings = StringUtils.split(javaToMysqlConfig, ",", true); |
| 583 | |
| 584 | if (mappings != null) { |
| 585 | Iterator mappingsIter = mappings.iterator(); |
| 586 | |
| 587 | while (mappingsIter.hasNext()) { |
| 588 | String aMapping = (String) mappingsIter.next(); |
| 589 | |
| 590 | List parsedPair = StringUtils.split(aMapping, "=", true); |
| 591 | |
| 592 | if (parsedPair.size() == 2) { |
| 593 | String key = parsedPair.get(0).toString(); |
| 594 | String value = parsedPair.get(1).toString(); |
| 595 | |
| 596 | if (addVersionedProperties) { |
| 597 | List versionedProperties = (List) mapToPopulate |
| 598 | .get(key); |
| 599 | |
| 600 | if (versionedProperties == null) { |
| 601 | versionedProperties = new ArrayList(); |
| 602 | mapToPopulate.put(key, versionedProperties); |
| 603 | } |
| 604 | |
| 605 | VersionedStringProperty verProp = new VersionedStringProperty( |
| 606 | value); |
| 607 | versionedProperties.add(verProp); |
| 608 | |
| 609 | if (addUppercaseKeys) { |
| 610 | String keyUc = key.toUpperCase(Locale.ENGLISH); |
| 611 | |
| 612 | versionedProperties = (List) mapToPopulate |
| 613 | .get(keyUc); |
| 614 | |
| 615 | if (versionedProperties == null) { |
| 616 | versionedProperties = new ArrayList(); |
| 617 | mapToPopulate.put(keyUc, |
| 618 | versionedProperties); |
| 619 | } |
| 620 | |
| 621 | versionedProperties.add(verProp); |
| 622 | } |
| 623 | } else { |
| 624 | mapToPopulate.put(key, value); |
| 625 | |
| 626 | if (addUppercaseKeys) { |
| 627 | mapToPopulate.put(key |
| 628 | .toUpperCase(Locale.ENGLISH), value); |
| 629 | } |
| 630 | } |
| 631 | } else { |
| 632 | throw new RuntimeException( |
| 633 | "Syntax error in Charsets.properties " |
| 634 | + "resource for token \"" + aMapping |
| 635 | + "\"."); |
| 636 | } |
| 637 | } |
| 638 | } else { |
| 639 | throw new RuntimeException("Missing/corrupt entry for \"" |
| 640 | + configKey + "\" in Charsets.properties."); |
| 641 | } |
| 642 | } else { |
| 643 | throw new RuntimeException("Could not find configuration value " |
| 644 | + "\"" + configKey + "\" in Charsets.properties resource"); |
| 645 | } |
| 646 | } |
| 647 | } |
| 648 | |
| 649 | class VersionedStringProperty { |
| 650 | int majorVersion, minorVersion, subminorVersion; |
| 651 | |
| 652 | boolean preferredValue = false; |
| 653 | |
| 654 | String propertyInfo; |
| 655 | |
| 656 | VersionedStringProperty(String property) { |
| 657 | property = property.trim(); |
| 658 | |
| 659 | if (property.startsWith("*")) { |
| 660 | property = property.substring(1); |
| 661 | preferredValue = true; |
| 662 | } |
| 663 | |
| 664 | if (property.startsWith(">")) { |
| 665 | property = property.substring(1); |
| 666 | |
| 667 | int charPos = 0; |
| 668 | |
| 669 | for (charPos = 0; charPos < property.length(); charPos++) { |
| 670 | char c = property.charAt(charPos); |
| 671 | |
| 672 | if (!Character.isWhitespace(c) && !Character.isDigit(c) |
| 673 | && c != '.') { |
| 674 | break; |
| 675 | } |
| 676 | } |
| 677 | |
| 678 | String versionInfo = property.substring(0, charPos); |
| 679 | List versionParts = StringUtils.split(versionInfo, ".", true); |
| 680 | |
| 681 | majorVersion = Integer.parseInt(versionParts.get(0).toString()); |
| 682 | |
| 683 | if (versionParts.size() > 1) { |
| 684 | minorVersion = Integer.parseInt(versionParts.get(1).toString()); |
| 685 | } else { |
| 686 | minorVersion = 0; |
| 687 | } |
| 688 | |
| 689 | if (versionParts.size() > 2) { |
| 690 | subminorVersion = Integer.parseInt(versionParts.get(2) |
| 691 | .toString()); |
| 692 | } else { |
| 693 | subminorVersion = 0; |
| 694 | } |
| 695 | |
| 696 | propertyInfo = property.substring(charPos); |
| 697 | } else { |
| 698 | majorVersion = minorVersion = subminorVersion = 0; |
| 699 | propertyInfo = property; |
| 700 | } |
| 701 | } |
| 702 | |
| 703 | VersionedStringProperty(String property, int major, int minor, int subminor) { |
| 704 | propertyInfo = property; |
| 705 | majorVersion = major; |
| 706 | minorVersion = minor; |
| 707 | subminorVersion = subminor; |
| 708 | } |
| 709 | |
| 710 | boolean isOkayForVersion(Connection conn) throws SQLException { |
| 711 | return conn.versionMeetsMinimum(majorVersion, minorVersion, |
| 712 | subminorVersion); |
| 713 | } |
| 714 | |
| 715 | public String toString() { |
| 716 | return propertyInfo; |
| 717 | } |
| 718 | } |