1 7 8 package java.lang; 9 10 import java.io.CharConversionException ; 11 import java.io.UnsupportedEncodingException ; 12 import java.lang.ref.SoftReference ; 13 import java.nio.ByteBuffer ; 14 import java.nio.CharBuffer ; 15 import java.nio.BufferOverflowException ; 16 import java.nio.BufferUnderflowException ; 17 import java.nio.charset.Charset ; 18 import java.nio.charset.CharsetDecoder ; 19 import java.nio.charset.CharsetEncoder ; 20 import java.nio.charset.CharacterCodingException ; 21 import java.nio.charset.CoderResult ; 22 import java.nio.charset.CodingErrorAction ; 23 import java.nio.charset.IllegalCharsetNameException ; 24 import java.nio.charset.MalformedInputException ; 25 import java.nio.charset.UnsupportedCharsetException ; 26 import sun.io.ByteToCharConverter; 27 import sun.io.CharToByteConverter; 28 import sun.io.Converters; 29 import sun.misc.MessageUtils; 30 import sun.nio.cs.HistoricallyNamedCharset; 31 32 33 36 37 class StringCoding { 38 39 private StringCoding() { } 40 41 43 private static ThreadLocal decoder = new ThreadLocal (); 44 private static ThreadLocal encoder = new ThreadLocal (); 45 46 private static boolean warnUnsupportedCharset = true; 47 48 private static Object deref(ThreadLocal tl) { 49 SoftReference sr = (SoftReference )tl.get(); 50 if (sr == null) 51 return null; 52 return sr.get(); 53 } 54 55 private static void set(ThreadLocal tl, Object ob) { 56 tl.set(new SoftReference (ob)); 57 } 58 59 private static byte[] trim(byte[] ba, int len) { 62 if (len == ba.length) 63 return ba; 64 byte[] tba = new byte[len]; 65 System.arraycopy(ba, 0, tba, 0, len); 66 return tba; 67 } 68 69 private static char[] trim(char[] ca, int len) { 72 if (len == ca.length) 73 return ca; 74 char[] tca = new char[len]; 75 System.arraycopy(ca, 0, tca, 0, len); 76 return tca; 77 } 78 79 private static int scale(int len, float expansionFactor) { 80 return (int)(len * (double)expansionFactor); 83 } 84 85 private static Charset lookupCharset(String csn) { 86 if (Charset.isSupported(csn)) { 87 try { 88 return Charset.forName(csn); 89 } catch (UnsupportedCharsetException x) { 90 throw new Error (x); 91 } 92 } 93 return null; 94 } 95 96 private static void warnUnsupportedCharset(String csn) { 97 if (warnUnsupportedCharset) { 98 MessageUtils.err("WARNING: Default charset " + csn + 102 " not supported, using ISO-8859-1 instead"); 103 warnUnsupportedCharset = false; 104 } 105 } 106 107 108 110 private static abstract class StringDecoder { 113 private final String requestedCharsetName; 114 protected StringDecoder(String requestedCharsetName) { 115 this.requestedCharsetName = requestedCharsetName; 116 } 117 final String requestedCharsetName() { 118 return requestedCharsetName; 119 } 120 abstract String charsetName(); 121 abstract char[] decode(byte[] ba, int off, int len); 122 } 123 124 private static class ConverterSD 127 extends StringDecoder 128 { 129 private ByteToCharConverter btc; 130 131 private ConverterSD(ByteToCharConverter btc, String rcn) { 132 super(rcn); 133 this.btc = btc; 134 } 135 136 String charsetName() { 137 return btc.getCharacterEncoding(); 138 } 139 140 char[] decode(byte[] ba, int off, int len) { 141 int en = scale(len, btc.getMaxCharsPerByte()); 142 char[] ca = new char[en]; 143 if (len == 0) 144 return ca; 145 btc.reset(); 146 int n = 0; 147 try { 148 n = btc.convert(ba, off, off + len, ca, 0, en); 149 n += btc.flush(ca, btc.nextCharIndex(), en); 150 } catch (CharConversionException x) { 151 n = btc.nextCharIndex(); 153 } 154 return trim(ca, n); 155 } 156 157 } 158 159 private static class CharsetSD 162 extends StringDecoder 163 { 164 private final Charset cs; 165 private final CharsetDecoder cd; 166 167 private CharsetSD(Charset cs, String rcn) { 168 super(rcn); 169 this.cs = cs; 170 this.cd = cs.newDecoder() 171 .onMalformedInput(CodingErrorAction.REPLACE) 172 .onUnmappableCharacter(CodingErrorAction.REPLACE); 173 } 174 175 String charsetName() { 176 if (cs instanceof HistoricallyNamedCharset) 177 return ((HistoricallyNamedCharset)cs).historicalName(); 178 return cs.name(); 179 } 180 181 char[] decode(byte[] ba, int off, int len) { 182 int en = scale(len, cd.maxCharsPerByte()); 183 char[] ca = new char[en]; 184 if (len == 0) 185 return ca; 186 cd.reset(); 187 ByteBuffer bb = ByteBuffer.wrap(ba, off, len); 188 CharBuffer cb = CharBuffer.wrap(ca); 189 try { 190 CoderResult cr = cd.decode(bb, cb, true); 191 if (!cr.isUnderflow()) 192 cr.throwException(); 193 cr = cd.flush(cb); 194 if (!cr.isUnderflow()) 195 cr.throwException(); 196 } catch (CharacterCodingException x) { 197 throw new Error (x); 200 } 201 return trim(ca, cb.position()); 202 } 203 204 } 205 206 static char[] decode(String charsetName, byte[] ba, int off, int len) 207 throws UnsupportedEncodingException 208 { 209 StringDecoder sd = (StringDecoder)deref(decoder); 210 String csn = (charsetName == null) ? "ISO-8859-1" : charsetName; 211 if ((sd == null) || !(csn.equals(sd.requestedCharsetName()) 212 || csn.equals(sd.charsetName()))) { 213 sd = null; 214 try { 215 Charset cs = lookupCharset(csn); 216 if (cs != null) 217 sd = new CharsetSD(cs, csn); 218 else 219 sd = null; 220 } catch (IllegalCharsetNameException x) { 221 } 223 if (sd == null) 224 sd = new ConverterSD(ByteToCharConverter.getConverter(csn), 225 csn); 226 set(decoder, sd); 227 } 228 return sd.decode(ba, off, len); 229 } 230 231 static char[] decode(byte[] ba, int off, int len) { 232 String csn = Converters.getDefaultEncodingName(); 233 try { 234 return decode(csn, ba, off, len); 235 } catch (UnsupportedEncodingException x) { 236 Converters.resetDefaultEncodingName(); 237 warnUnsupportedCharset(csn); 238 } 239 try { 240 return decode("ISO-8859-1", ba, off, len); 241 } catch (UnsupportedEncodingException x) { 242 MessageUtils.err("ISO-8859-1 charset not available: " 245 + x.toString()); 246 System.exit(1); 249 return null; 250 } 251 } 252 253 254 255 256 258 private static abstract class StringEncoder { 261 private final String requestedCharsetName; 262 protected StringEncoder(String requestedCharsetName) { 263 this.requestedCharsetName = requestedCharsetName; 264 } 265 final String requestedCharsetName() { 266 return requestedCharsetName; 267 } 268 abstract String charsetName(); 269 abstract byte[] encode(char[] cs, int off, int len); 270 } 271 272 private static class ConverterSE 275 extends StringEncoder 276 { 277 private CharToByteConverter ctb; 278 279 private ConverterSE(CharToByteConverter ctb, String rcn) { 280 super(rcn); 281 this.ctb = ctb; 282 } 283 284 String charsetName() { 285 return ctb.getCharacterEncoding(); 286 } 287 288 byte[] encode(char[] ca, int off, int len) { 289 int en = scale(len, ctb.getMaxBytesPerChar()); 290 byte[] ba = new byte[en]; 291 if (len == 0) 292 return ba; 293 294 ctb.reset(); 295 int n; 296 try { 297 n = ctb.convertAny(ca, off, (off + len), 298 ba, 0, en); 299 n += ctb.flushAny(ba, ctb.nextByteIndex(), en); 300 } catch (CharConversionException x) { 301 throw new Error ("Converter malfunction: " + 302 ctb.getClass().getName(), 303 x); 304 } 305 return trim(ba, n); 306 } 307 308 } 309 310 private static class CharsetSE 313 extends StringEncoder 314 { 315 private Charset cs; 316 private CharsetEncoder ce; 317 318 private CharsetSE(Charset cs, String rcn) { 319 super(rcn); 320 this.cs = cs; 321 this.ce = cs.newEncoder() 322 .onMalformedInput(CodingErrorAction.REPLACE) 323 .onUnmappableCharacter(CodingErrorAction.REPLACE); 324 } 325 326 String charsetName() { 327 if (cs instanceof HistoricallyNamedCharset) 328 return ((HistoricallyNamedCharset)cs).historicalName(); 329 return cs.name(); 330 } 331 332 byte[] encode(char[] ca, int off, int len) { 333 int en = scale(len, ce.maxBytesPerChar()); 334 byte[] ba = new byte[en]; 335 if (len == 0) 336 return ba; 337 338 ce.reset(); 339 ByteBuffer bb = ByteBuffer.wrap(ba); 340 CharBuffer cb = CharBuffer.wrap(ca, off, len); 341 try { 342 CoderResult cr = ce.encode(cb, bb, true); 343 if (!cr.isUnderflow()) 344 cr.throwException(); 345 cr = ce.flush(bb); 346 if (!cr.isUnderflow()) 347 cr.throwException(); 348 } catch (CharacterCodingException x) { 349 throw new Error (x); 352 } 353 return trim(ba, bb.position()); 354 } 355 356 } 357 358 static byte[] encode(String charsetName, char[] ca, int off, int len) 359 throws UnsupportedEncodingException 360 { 361 StringEncoder se = (StringEncoder)deref(encoder); 362 String csn = (charsetName == null) ? "ISO-8859-1" : charsetName; 363 if ((se == null) || !(csn.equals(se.requestedCharsetName()) 364 || csn.equals(se.charsetName()))) { 365 se = null; 366 try { 367 Charset cs = lookupCharset(csn); 368 if (cs != null) 369 se = new CharsetSE(cs, csn); 370 } catch (IllegalCharsetNameException x) { 371 } 373 if (se == null) 374 se = new ConverterSE(CharToByteConverter.getConverter(csn), 375 csn); 376 set(encoder, se); 377 } 378 return se.encode(ca, off, len); 379 } 380 381 static byte[] encode(char[] ca, int off, int len) { 382 String csn = Converters.getDefaultEncodingName(); 383 try { 384 return encode(csn, ca, off, len); 385 } catch (UnsupportedEncodingException x) { 386 Converters.resetDefaultEncodingName(); 387 warnUnsupportedCharset(csn); 388 } 389 try { 390 return encode("ISO-8859-1", ca, off, len); 391 } catch (UnsupportedEncodingException x) { 392 MessageUtils.err("ISO-8859-1 charset not available: " 395 + x.toString()); 396 System.exit(1); 399 return null; 400 } 401 } 402 403 } 404 | Popular Tags |