1 /* 2 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.nio.cs.ext; 27 28 import java.util.Collections; 29 import java.util.ArrayList; 30 import java.util.HashMap; 31 import java.util.List; 32 import java.util.Map; 33 import java.nio.charset.*; 34 35 final class CompoundTextSupport { 36 37 private static final class ControlSequence { 38 39 final int hash; 40 final byte[] escSequence; 41 final byte[] encoding; 42 43 ControlSequence(byte[] escSequence) { 44 this(escSequence, null); 45 } 46 ControlSequence(byte[] escSequence, byte[] encoding) { 47 if (escSequence == null) { 48 throw new NullPointerException(); 49 } 50 51 this.escSequence = escSequence; 52 this.encoding = encoding; 53 54 int hash = 0; 55 int length = escSequence.length; 56 57 for (int i = 0; i < escSequence.length; i++) { 58 hash += (((int)escSequence[i]) & 0xff) << (i % 4); 59 } 60 if (encoding != null) { 61 for (int i = 0; i < encoding.length; i++) { 62 hash += (((int)encoding[i]) & 0xff) << (i % 4); 63 } 64 length += 2 /* M L */ + encoding.length + 1 /* 0x02 */; 65 } 66 67 this.hash = hash; 68 69 if (MAX_CONTROL_SEQUENCE_LEN < length) { 70 MAX_CONTROL_SEQUENCE_LEN = length; 71 } 72 } 73 74 public boolean equals(Object obj) { 75 if (this == obj) { 76 return true; 77 } 78 if (!(obj instanceof ControlSequence)) { 79 return false; 80 } 81 ControlSequence rhs = (ControlSequence)obj; 82 if (escSequence != rhs.escSequence) { 83 if (escSequence.length != rhs.escSequence.length) { 84 return false; 85 } 86 for (int i = 0; i < escSequence.length; i++) { 87 if (escSequence[i] != rhs.escSequence[i]) { 88 return false; 89 } 90 } 91 } 92 if (encoding != rhs.encoding) { 93 if (encoding == null || rhs.encoding == null || 94 encoding.length != rhs.encoding.length) 95 { 96 return false; 97 } 98 for (int i = 0; i < encoding.length; i++) { 99 if (encoding[i] != rhs.encoding[i]) { 100 return false; 101 } 102 } 103 } 104 return true; 105 } 106 107 public int hashCode() { 108 return hash; 109 } 110 111 ControlSequence concatenate(ControlSequence rhs) { 112 if (encoding != null) { 113 throw new IllegalArgumentException 114 ("cannot concatenate to a non-standard charset escape " + 115 "sequence"); 116 } 117 118 int len = escSequence.length + rhs.escSequence.length; 119 byte[] newEscSequence = new byte[len]; 120 System.arraycopy(escSequence, 0, newEscSequence, 0, 121 escSequence.length); 122 System.arraycopy(rhs.escSequence, 0, newEscSequence, 123 escSequence.length, rhs.escSequence.length); 124 return new ControlSequence(newEscSequence, rhs.encoding); 125 } 126 } 127 128 static int MAX_CONTROL_SEQUENCE_LEN; 129 130 /** 131 * Maps a GL or GR escape sequence to an encoding. 132 */ 133 private static final Map<ControlSequence, String> sequenceToEncodingMap; 134 135 /** 136 * Indicates whether a particular encoding wants the high bit turned on 137 * or off. 138 */ 139 private static final Map<ControlSequence, Boolean> highBitsMap; 140 141 /** 142 * Maps an encoding to an escape sequence. Rather than manage two 143 * converters in CharToByteCOMPOUND_TEXT, we output escape sequences which 144 * modify both GL and GR if necessary. This makes the output slightly less 145 * efficient, but our code much simpler. 146 */ 147 private static final Map<String, ControlSequence> encodingToSequenceMap; 148 149 /** 150 * The keys of 'encodingToSequenceMap', sorted in preferential order. 151 */ 152 private static final List<String> encodings; 153 154 static { 155 HashMap<ControlSequence, String> tSequenceToEncodingMap = 156 new HashMap<>(33, 1.0f); 157 HashMap<ControlSequence, Boolean> tHighBitsMap = 158 new HashMap<>(31, 1.0f); 159 HashMap<String, ControlSequence> tEncodingToSequenceMap = 160 new HashMap<>(21, 1.0f); 161 ArrayList<String> tEncodings = new ArrayList<>(21); 162 163 if (!(isEncodingSupported("US-ASCII") && 164 isEncodingSupported("ISO-8859-1"))) 165 { 166 throw new ExceptionInInitializerError 167 ("US-ASCII and ISO-8859-1 unsupported"); 168 } 169 170 ControlSequence leftAscii = // high bit off, leave off 171 new ControlSequence(new byte[] { 0x1B, 0x28, 0x42 }); 172 tSequenceToEncodingMap.put(leftAscii, "US-ASCII"); 173 tHighBitsMap.put(leftAscii, Boolean.FALSE); 174 175 { 176 ControlSequence rightAscii = // high bit on, turn off 177 new ControlSequence(new byte[] { 0x1B, 0x29, 0x42 }); 178 tSequenceToEncodingMap.put(rightAscii, "US-ASCII"); 179 tHighBitsMap.put(rightAscii, Boolean.FALSE); 180 } 181 182 { 183 ControlSequence rightHalf = // high bit on, leave on 184 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x41 }); 185 tSequenceToEncodingMap.put(rightHalf, "ISO-8859-1"); 186 tHighBitsMap.put(rightHalf, Boolean.TRUE); 187 188 ControlSequence fullSet = leftAscii.concatenate(rightHalf); 189 tEncodingToSequenceMap.put("ISO-8859-1", fullSet); 190 tEncodings.add("ISO-8859-1"); 191 } 192 if (isEncodingSupported("ISO-8859-2")) { 193 ControlSequence rightHalf = // high bit on, leave on 194 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x42 }); 195 tSequenceToEncodingMap.put(rightHalf, "ISO-8859-2"); 196 tHighBitsMap.put(rightHalf, Boolean.TRUE); 197 198 ControlSequence fullSet = leftAscii.concatenate(rightHalf); 199 tEncodingToSequenceMap.put("ISO-8859-2", fullSet); 200 tEncodings.add("ISO-8859-2"); 201 } 202 if (isEncodingSupported("ISO-8859-3")) { 203 ControlSequence rightHalf = // high bit on, leave on 204 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x43 }); 205 tSequenceToEncodingMap.put(rightHalf, "ISO-8859-3"); 206 tHighBitsMap.put(rightHalf, Boolean.TRUE); 207 208 ControlSequence fullSet = leftAscii.concatenate(rightHalf); 209 tEncodingToSequenceMap.put("ISO-8859-3", fullSet); 210 tEncodings.add("ISO-8859-3"); 211 } 212 if (isEncodingSupported("ISO-8859-4")) { 213 ControlSequence rightHalf = // high bit on, leave on 214 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x44 }); 215 tSequenceToEncodingMap.put(rightHalf, "ISO-8859-4"); 216 tHighBitsMap.put(rightHalf, Boolean.TRUE); 217 218 ControlSequence fullSet = leftAscii.concatenate(rightHalf); 219 tEncodingToSequenceMap.put("ISO-8859-4", fullSet); 220 tEncodings.add("ISO-8859-4"); 221 } 222 if (isEncodingSupported("ISO-8859-5")) { 223 ControlSequence rightHalf = // high bit on, leave on 224 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x4C }); 225 tSequenceToEncodingMap.put(rightHalf, "ISO-8859-5"); 226 tHighBitsMap.put(rightHalf, Boolean.TRUE); 227 228 ControlSequence fullSet = leftAscii.concatenate(rightHalf); 229 tEncodingToSequenceMap.put("ISO-8859-5", fullSet); 230 tEncodings.add("ISO-8859-5"); 231 } 232 if (isEncodingSupported("ISO-8859-6")) { 233 ControlSequence rightHalf = // high bit on, leave on 234 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x47 }); 235 tSequenceToEncodingMap.put(rightHalf, "ISO-8859-6"); 236 tHighBitsMap.put(rightHalf, Boolean.TRUE); 237 238 ControlSequence fullSet = leftAscii.concatenate(rightHalf); 239 tEncodingToSequenceMap.put("ISO-8859-6", fullSet); 240 tEncodings.add("ISO-8859-6"); 241 } 242 if (isEncodingSupported("ISO-8859-7")) { 243 ControlSequence rightHalf = // high bit on, leave on 244 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x46 }); 245 tSequenceToEncodingMap.put(rightHalf, "ISO-8859-7"); 246 tHighBitsMap.put(rightHalf, Boolean.TRUE); 247 248 ControlSequence fullSet = leftAscii.concatenate(rightHalf); 249 tEncodingToSequenceMap.put("ISO-8859-7", fullSet); 250 tEncodings.add("ISO-8859-7"); 251 } 252 if (isEncodingSupported("ISO-8859-8")) { 253 ControlSequence rightHalf = // high bit on, leave on 254 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x48 }); 255 tSequenceToEncodingMap.put(rightHalf, "ISO-8859-8"); 256 tHighBitsMap.put(rightHalf, Boolean.TRUE); 257 258 ControlSequence fullSet = leftAscii.concatenate(rightHalf); 259 tEncodingToSequenceMap.put("ISO-8859-8", fullSet); 260 tEncodings.add("ISO-8859-8"); 261 } 262 if (isEncodingSupported("ISO-8859-9")) { 263 ControlSequence rightHalf = // high bit on, leave on 264 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x4D }); 265 tSequenceToEncodingMap.put(rightHalf, "ISO-8859-9"); 266 tHighBitsMap.put(rightHalf, Boolean.TRUE); 267 268 ControlSequence fullSet = leftAscii.concatenate(rightHalf); 269 tEncodingToSequenceMap.put("ISO-8859-9", fullSet); 270 tEncodings.add("ISO-8859-9"); 271 } 272 if (isEncodingSupported("JIS_X0201")) { 273 ControlSequence glLeft = // high bit off, leave off 274 new ControlSequence(new byte[] { 0x1B, 0x28, 0x4A }); 275 ControlSequence glRight = // high bit off, turn on 276 new ControlSequence(new byte[] { 0x1B, 0x28, 0x49 }); 277 ControlSequence grLeft = // high bit on, turn off 278 new ControlSequence(new byte[] { 0x1B, 0x29, 0x4A }); 279 ControlSequence grRight = // high bit on, leave on 280 new ControlSequence(new byte[] { 0x1B, 0x29, 0x49 }); 281 tSequenceToEncodingMap.put(glLeft, "JIS_X0201"); 282 tSequenceToEncodingMap.put(glRight, "JIS_X0201"); 283 tSequenceToEncodingMap.put(grLeft, "JIS_X0201"); 284 tSequenceToEncodingMap.put(grRight, "JIS_X0201"); 285 tHighBitsMap.put(glLeft, Boolean.FALSE); 286 tHighBitsMap.put(glRight, Boolean.TRUE); 287 tHighBitsMap.put(grLeft, Boolean.FALSE); 288 tHighBitsMap.put(grRight, Boolean.TRUE); 289 290 ControlSequence fullSet = glLeft.concatenate(grRight); 291 tEncodingToSequenceMap.put("JIS_X0201", fullSet); 292 tEncodings.add("JIS_X0201"); 293 } 294 if (isEncodingSupported("X11GB2312")) { 295 ControlSequence leftHalf = // high bit off, leave off 296 new ControlSequence(new byte[] { 0x1B, 0x24, 0x28, 0x41 }); 297 ControlSequence rightHalf = // high bit on, turn off 298 new ControlSequence(new byte[] { 0x1B, 0x24, 0x29, 0x41 }); 299 tSequenceToEncodingMap.put(leftHalf, "X11GB2312"); 300 tSequenceToEncodingMap.put(rightHalf, "X11GB2312"); 301 tHighBitsMap.put(leftHalf, Boolean.FALSE); 302 tHighBitsMap.put(rightHalf, Boolean.FALSE); 303 304 tEncodingToSequenceMap.put("X11GB2312", leftHalf); 305 tEncodings.add("X11GB2312"); 306 } 307 if (isEncodingSupported("x-JIS0208")) { 308 ControlSequence leftHalf = // high bit off, leave off 309 new ControlSequence(new byte[] { 0x1B, 0x24, 0x28, 0x42 }); 310 ControlSequence rightHalf = // high bit on, turn off 311 new ControlSequence(new byte[] { 0x1B, 0x24, 0x29, 0x42 }); 312 tSequenceToEncodingMap.put(leftHalf, "x-JIS0208"); 313 tSequenceToEncodingMap.put(rightHalf, "x-JIS0208"); 314 tHighBitsMap.put(leftHalf, Boolean.FALSE); 315 tHighBitsMap.put(rightHalf, Boolean.FALSE); 316 317 tEncodingToSequenceMap.put("x-JIS0208", leftHalf); 318 tEncodings.add("x-JIS0208"); 319 } 320 if (isEncodingSupported("X11KSC5601")) { 321 ControlSequence leftHalf = // high bit off, leave off 322 new ControlSequence(new byte[] { 0x1B, 0x24, 0x28, 0x43 }); 323 ControlSequence rightHalf = // high bit on, turn off 324 new ControlSequence(new byte[] { 0x1B, 0x24, 0x29, 0x43 }); 325 tSequenceToEncodingMap.put(leftHalf, "X11KSC5601"); 326 tSequenceToEncodingMap.put(rightHalf, "X11KSC5601"); 327 tHighBitsMap.put(leftHalf, Boolean.FALSE); 328 tHighBitsMap.put(rightHalf, Boolean.FALSE); 329 330 tEncodingToSequenceMap.put("X11KSC5601", leftHalf); 331 tEncodings.add("X11KSC5601"); 332 } 333 334 // Encodings not listed in Compound Text Encoding spec 335 336 // Esc seq: -b 337 if (isEncodingSupported("ISO-8859-15")) { 338 ControlSequence rightHalf = // high bit on, leave on 339 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x62 }); 340 tSequenceToEncodingMap.put(rightHalf, "ISO-8859-15"); 341 tHighBitsMap.put(rightHalf, Boolean.TRUE); 342 343 ControlSequence fullSet = leftAscii.concatenate(rightHalf); 344 tEncodingToSequenceMap.put("ISO-8859-15", fullSet); 345 tEncodings.add("ISO-8859-15"); 346 } 347 // Esc seq: -T 348 if (isEncodingSupported("TIS-620")) { 349 ControlSequence rightHalf = // high bit on, leave on 350 new ControlSequence(new byte[] { 0x1B, 0x2D, 0x54 }); 351 tSequenceToEncodingMap.put(rightHalf, "TIS-620"); 352 tHighBitsMap.put(rightHalf, Boolean.TRUE); 353 354 ControlSequence fullSet = leftAscii.concatenate(rightHalf); 355 tEncodingToSequenceMap.put("TIS-620", fullSet); 356 tEncodings.add("TIS-620"); 357 } 358 if (isEncodingSupported("JIS_X0212-1990")) { 359 ControlSequence leftHalf = // high bit off, leave off 360 new ControlSequence(new byte[] { 0x1B, 0x24, 0x28, 0x44 }); 361 ControlSequence rightHalf = // high bit on, turn off 362 new ControlSequence(new byte[] { 0x1B, 0x24, 0x29, 0x44 }); 363 tSequenceToEncodingMap.put(leftHalf, "JIS_X0212-1990"); 364 tSequenceToEncodingMap.put(rightHalf, "JIS_X0212-1990"); 365 tHighBitsMap.put(leftHalf, Boolean.FALSE); 366 tHighBitsMap.put(rightHalf, Boolean.FALSE); 367 368 tEncodingToSequenceMap.put("JIS_X0212-1990", leftHalf); 369 tEncodings.add("JIS_X0212-1990"); 370 } 371 if (isEncodingSupported("X11CNS11643P1")) { 372 ControlSequence leftHalf = // high bit off, leave off 373 new ControlSequence(new byte[] { 0x1B, 0x24, 0x28, 0x47 }); 374 ControlSequence rightHalf = // high bit on, turn off 375 new ControlSequence(new byte[] { 0x1B, 0x24, 0x29, 0x47 }); 376 tSequenceToEncodingMap.put(leftHalf, "X11CNS11643P1"); 377 tSequenceToEncodingMap.put(rightHalf, "X11CNS11643P1"); 378 tHighBitsMap.put(leftHalf, Boolean.FALSE); 379 tHighBitsMap.put(rightHalf, Boolean.FALSE); 380 381 tEncodingToSequenceMap.put("X11CNS11643P1", leftHalf); 382 tEncodings.add("X11CNS11643P1"); 383 } 384 if (isEncodingSupported("X11CNS11643P2")) { 385 ControlSequence leftHalf = // high bit off, leave off 386 new ControlSequence(new byte[] { 0x1B, 0x24, 0x28, 0x48 }); 387 ControlSequence rightHalf = // high bit on, turn off 388 new ControlSequence(new byte[] { 0x1B, 0x24, 0x29, 0x48 }); 389 tSequenceToEncodingMap.put(leftHalf, "X11CNS11643P2"); 390 tSequenceToEncodingMap.put(rightHalf, "X11CNS11643P2"); 391 tHighBitsMap.put(leftHalf, Boolean.FALSE); 392 tHighBitsMap.put(rightHalf, Boolean.FALSE); 393 394 tEncodingToSequenceMap.put("X11CNS11643P2", leftHalf); 395 tEncodings.add("X11CNS11643P2"); 396 } 397 if (isEncodingSupported("X11CNS11643P3")) { 398 ControlSequence leftHalf = // high bit off, leave off 399 new ControlSequence(new byte[] { 0x1B, 0x24, 0x28, 0x49 }); 400 ControlSequence rightHalf = // high bit on, turn off 401 new ControlSequence(new byte[] { 0x1B, 0x24, 0x29, 0x49 }); 402 tSequenceToEncodingMap.put(leftHalf, "X11CNS11643P3"); 403 tSequenceToEncodingMap.put(rightHalf, "X11CNS11643P3"); 404 tHighBitsMap.put(leftHalf, Boolean.FALSE); 405 tHighBitsMap.put(rightHalf, Boolean.FALSE); 406 407 tEncodingToSequenceMap.put("X11CNS11643P3", leftHalf); 408 tEncodings.add("X11CNS11643P3"); 409 } 410 // Esc seq: %/2??SUN-KSC5601.1992-3 411 if (isEncodingSupported("x-Johab")) { 412 // 0x32 looks wrong. It's copied from the Sun X11 Compound Text 413 // support code. It implies that all Johab characters comprise two 414 // octets, which isn't true. Johab supports the ASCII/KS-Roman 415 // characters from 0x21-0x7E with single-byte representations. 416 ControlSequence johab = new ControlSequence( 417 new byte[] { 0x1b, 0x25, 0x2f, 0x32 }, 418 new byte[] { 0x53, 0x55, 0x4e, 0x2d, 0x4b, 0x53, 0x43, 0x35, 419 0x36, 0x30, 0x31, 0x2e, 0x31, 0x39, 0x39, 0x32, 420 0x2d, 0x33 }); 421 tSequenceToEncodingMap.put(johab, "x-Johab"); 422 tEncodingToSequenceMap.put("x-Johab", johab); 423 tEncodings.add("x-Johab"); 424 } 425 // Esc seq: %/2??SUN-BIG5-1 426 if (isEncodingSupported("Big5")) { 427 // 0x32 looks wrong. It's copied from the Sun X11 Compound Text 428 // support code. It implies that all Big5 characters comprise two 429 // octets, which isn't true. Big5 supports the ASCII/CNS-Roman 430 // characters from 0x21-0x7E with single-byte representations. 431 ControlSequence big5 = new ControlSequence( 432 new byte[] { 0x1b, 0x25, 0x2f, 0x32 }, 433 new byte[] { 0x53, 0x55, 0x4e, 0x2d, 0x42, 0x49, 0x47, 0x35, 434 0x2d, 0x31 }); 435 tSequenceToEncodingMap.put(big5, "Big5"); 436 tEncodingToSequenceMap.put("Big5", big5); 437 tEncodings.add("Big5"); 438 } 439 440 sequenceToEncodingMap = 441 Collections.unmodifiableMap(tSequenceToEncodingMap); 442 highBitsMap = Collections.unmodifiableMap(tHighBitsMap); 443 encodingToSequenceMap = 444 Collections.unmodifiableMap(tEncodingToSequenceMap); 445 encodings = Collections.unmodifiableList(tEncodings); 446 } 447 448 private static boolean isEncodingSupported(String encoding) { 449 try { 450 if (Charset.isSupported(encoding)) 451 return true; 452 } catch (IllegalArgumentException x) { } 453 return (getDecoder(encoding) != null && 454 getEncoder(encoding) != null); 455 } 456 457 458 // For Decoder 459 static CharsetDecoder getStandardDecoder(byte[] escSequence) { 460 return getNonStandardDecoder(escSequence, null); 461 } 462 static boolean getHighBit(byte[] escSequence) { 463 Boolean bool = highBitsMap.get(new ControlSequence(escSequence)); 464 return (bool == Boolean.TRUE); 465 } 466 static CharsetDecoder getNonStandardDecoder(byte[] escSequence, 467 byte[] encoding) { 468 return getDecoder(sequenceToEncodingMap.get 469 (new ControlSequence(escSequence, encoding))); 470 } 471 static CharsetDecoder getDecoder(String enc) { 472 if (enc == null) { 473 return null; 474 } 475 Charset cs = null; 476 try { 477 cs = Charset.forName(enc); 478 } catch (IllegalArgumentException e) { 479 Class<?> cls; 480 try { 481 cls = Class.forName("sun.awt.motif." + enc); 482 } catch (ClassNotFoundException ee) { 483 return null; 484 } 485 try { 486 cs = (Charset)cls.newInstance(); 487 } catch (InstantiationException ee) { 488 return null; 489 } catch (IllegalAccessException ee) { 490 return null; 491 } 492 } 493 try { 494 return cs.newDecoder(); 495 } catch (UnsupportedOperationException e) {} 496 return null; 497 } 498 499 500 // For Encoder 501 static byte[] getEscapeSequence(String encoding) { 502 ControlSequence seq = encodingToSequenceMap.get(encoding); 503 if (seq != null) { 504 return seq.escSequence; 505 } 506 return null; 507 } 508 static byte[] getEncoding(String encoding) { 509 ControlSequence seq = encodingToSequenceMap.get(encoding); 510 if (seq != null) { 511 return seq.encoding; 512 } 513 return null; 514 } 515 static List<String> getEncodings() { 516 return encodings; 517 } 518 static CharsetEncoder getEncoder(String enc) { 519 if (enc == null) { 520 return null; 521 } 522 Charset cs = null; 523 try { 524 cs = Charset.forName(enc); 525 } catch (IllegalArgumentException e) { 526 Class<?> cls; 527 try { 528 cls = Class.forName("sun.awt.motif." + enc); 529 } catch (ClassNotFoundException ee) { 530 return null; 531 } 532 try { 533 cs = (Charset)cls.newInstance(); 534 } catch (InstantiationException ee) { 535 return null; 536 } catch (IllegalAccessException ee) { 537 return null; 538 } 539 } 540 try { 541 return cs.newEncoder(); 542 } catch (Throwable e) {} 543 return null; 544 } 545 546 // Not an instantiable class 547 private CompoundTextSupport() {} 548 }