1 /* 2 * Copyright (c) 2002, 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 /* 27 */ 28 29 package sun.nio.cs.ext; 30 31 import java.nio.ByteBuffer; 32 import java.nio.CharBuffer; 33 import java.nio.charset.Charset; 34 import java.nio.charset.CharsetDecoder; 35 import java.nio.charset.CharsetEncoder; 36 import java.nio.charset.CoderResult; 37 import sun.nio.cs.HistoricallyNamedCharset; 38 import sun.nio.cs.Surrogate; 39 40 public class EUC_JP 41 extends Charset 42 implements HistoricallyNamedCharset 43 { 44 public EUC_JP() { 45 super("EUC-JP", ExtendedCharsets.aliasesFor("EUC-JP")); 46 } 47 48 public String historicalName() { 49 return "EUC_JP"; 50 } 51 52 public boolean contains(Charset cs) { 53 return ((cs.name().equals("US-ASCII")) 54 || (cs instanceof JIS_X_0201) 55 || (cs instanceof JIS_X_0208) 56 || (cs instanceof JIS_X_0212) 57 || (cs instanceof EUC_JP)); 58 } 59 60 public CharsetDecoder newDecoder() { 61 return new Decoder(this); 62 } 63 64 public CharsetEncoder newEncoder() { 65 66 // Need to force the replacement byte to 0x3f 67 // because JIS_X_0208_Encoder defines its own 68 // alternative 2 byte substitution to permit it 69 // to exist as a self-standing Encoder 70 71 byte[] replacementBytes = { (byte)0x3f }; 72 return new Encoder(this).replaceWith(replacementBytes); 73 } 74 75 76 static class Decoder extends JIS_X_0208_Decoder 77 implements DelegatableDecoder { 78 79 JIS_X_0201.Decoder decoderJ0201; 80 JIS_X_0212_Decoder decoderJ0212; 81 82 private static final short[] j0208Index1 = 83 JIS_X_0208_Decoder.getIndex1(); 84 private static final String[] j0208Index2 = 85 JIS_X_0208_Decoder.getIndex2(); 86 87 protected Decoder(Charset cs) { 88 super(cs); 89 decoderJ0201 = new JIS_X_0201.Decoder(cs); 90 decoderJ0212 = new JIS_X_0212_Decoder(cs); 91 start = 0xa1; 92 end = 0xfe; 93 } 94 protected char decode0212(int byte1, int byte2) { 95 return decoderJ0212.decodeDouble(byte1, byte2); 96 } 97 98 protected char decodeDouble(int byte1, int byte2) { 99 if (byte1 == 0x8e) { 100 return decoderJ0201.decode(byte2 - 256); 101 } 102 // Fix for bug 4121358 - similar fix for bug 4117820 put 103 // into ByteToCharDoubleByte.getUnicode() 104 if (((byte1 < 0) || (byte1 > getIndex1().length)) 105 || ((byte2 < start) || (byte2 > end))) 106 return REPLACE_CHAR; 107 108 int n = (j0208Index1[byte1 - 0x80] & 0xf) * (end - start + 1) 109 + (byte2 - start); 110 return j0208Index2[j0208Index1[byte1 - 0x80] >> 4].charAt(n); 111 } 112 113 private CoderResult decodeArrayLoop(ByteBuffer src, 114 CharBuffer dst) 115 { 116 byte[] sa = src.array(); 117 int sp = src.arrayOffset() + src.position(); 118 int sl = src.arrayOffset() + src.limit(); 119 assert (sp <= sl); 120 sp = (sp <= sl ? sp : sl); 121 122 char[] da = dst.array(); 123 int dp = dst.arrayOffset() + dst.position(); 124 int dl = dst.arrayOffset() + dst.limit(); 125 assert (dp <= dl); 126 dp = (dp <= dl ? dp : dl); 127 128 int b1 = 0, b2 = 0; 129 int inputSize = 0; 130 char outputChar = REPLACE_CHAR; // U+FFFD; 131 132 try { 133 while (sp < sl) { 134 b1 = sa[sp] & 0xff; 135 inputSize = 1; 136 137 if ((b1 & 0x80) == 0) { 138 outputChar = (char)b1; 139 } 140 else { // Multibyte char 141 if ((b1 & 0xff) == 0x8f) { // JIS0212 142 if (sp + 3 > sl) 143 return CoderResult.UNDERFLOW; 144 b1 = sa[sp + 1] & 0xff; 145 b2 = sa[sp + 2] & 0xff; 146 inputSize += 2; 147 outputChar = decode0212(b1-0x80, b2-0x80); 148 } else { 149 // JIS0208 150 if (sp + 2 > sl) 151 return CoderResult.UNDERFLOW; 152 b2 = sa[sp + 1] & 0xff; 153 inputSize++; 154 outputChar = decodeDouble(b1, b2); 155 } 156 } 157 if (outputChar == REPLACE_CHAR) { // can't be decoded 158 return CoderResult.unmappableForLength(inputSize); 159 } 160 if (dp + 1 > dl) 161 return CoderResult.OVERFLOW; 162 da[dp++] = outputChar; 163 sp += inputSize; 164 } 165 return CoderResult.UNDERFLOW; 166 } finally { 167 src.position(sp - src.arrayOffset()); 168 dst.position(dp - dst.arrayOffset()); 169 } 170 } 171 172 private CoderResult decodeBufferLoop(ByteBuffer src, 173 CharBuffer dst) 174 { 175 int mark = src.position(); 176 int b1 = 0, b2 = 0; 177 int inputSize = 0; 178 179 char outputChar = REPLACE_CHAR; // U+FFFD; 180 181 try { 182 while (src.hasRemaining()) { 183 b1 = src.get() & 0xff; 184 inputSize = 1; 185 186 if ((b1 & 0x80) == 0) { 187 outputChar = (char)b1; 188 } else { // Multibyte char 189 if ((b1 & 0xff) == 0x8f) { // JIS0212 190 if (src.remaining() < 2) 191 return CoderResult.UNDERFLOW; 192 b1 = src.get() & 0xff; 193 b2 = src.get() & 0xff; 194 inputSize += 2; 195 outputChar = decode0212(b1-0x80, b2-0x80); 196 } else { 197 // JIS0208 198 if (src.remaining() < 1) 199 return CoderResult.UNDERFLOW; 200 b2 = src.get() & 0xff; 201 inputSize++; 202 outputChar = decodeDouble(b1, b2); 203 } 204 } 205 206 if (outputChar == REPLACE_CHAR) { 207 return CoderResult.unmappableForLength(inputSize); 208 } 209 if (dst.remaining() < 1) 210 return CoderResult.OVERFLOW; 211 dst.put(outputChar); 212 mark += inputSize; 213 } 214 return CoderResult.UNDERFLOW; 215 } finally { 216 src.position(mark); 217 } 218 } 219 220 // Make some protected methods public for use by JISAutoDetect 221 public CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) { 222 if (src.hasArray() && dst.hasArray()) 223 return decodeArrayLoop(src, dst); 224 else 225 return decodeBufferLoop(src, dst); 226 } 227 public void implReset() { 228 super.implReset(); 229 } 230 public CoderResult implFlush(CharBuffer out) { 231 return super.implFlush(out); 232 } 233 } 234 235 236 static class Encoder extends JIS_X_0208_Encoder { 237 238 JIS_X_0201.Encoder encoderJ0201; 239 JIS_X_0212_Encoder encoderJ0212; 240 241 private static final short[] j0208Index1 = 242 JIS_X_0208_Encoder.getIndex1(); 243 private static final String[] j0208Index2 = 244 JIS_X_0208_Encoder.getIndex2(); 245 246 private final Surrogate.Parser sgp = new Surrogate.Parser(); 247 248 protected Encoder(Charset cs) { 249 super(cs, 3.0f, 3.0f); 250 encoderJ0201 = new JIS_X_0201.Encoder(cs); 251 encoderJ0212 = new JIS_X_0212_Encoder(cs); 252 } 253 254 public boolean canEncode(char c) { 255 byte[] encodedBytes = new byte[3]; 256 257 if (encodeSingle(c, encodedBytes) == 0) { //doublebyte 258 if (encodeDouble(c) == 0) 259 return false; 260 } 261 return true; 262 } 263 264 protected int encodeSingle(char inputChar, byte[] outputByte) { 265 byte b; 266 267 if (inputChar == 0) { 268 outputByte[0] = (byte)0; 269 return 1; 270 } 271 272 if ((b = encoderJ0201.encode(inputChar)) == 0) 273 return 0; 274 275 if (b > 0 && b < 128) { 276 outputByte[0] = b; 277 return 1; 278 } 279 280 outputByte[0] = (byte)0x8e; 281 outputByte[1] = b; 282 return 2; 283 } 284 285 protected int encodeDouble(char ch) { 286 int offset = j0208Index1[((ch & 0xff00) >> 8 )] << 8; 287 int r = j0208Index2[offset >> 12].charAt((offset & 0xfff) + 288 (ch & 0xff)); 289 if (r != 0) 290 return r + 0x8080; 291 r = encoderJ0212.encodeDouble(ch); 292 if (r == 0) 293 return r; 294 return r + 0x8F8080; 295 } 296 297 private CoderResult encodeArrayLoop(CharBuffer src, 298 ByteBuffer dst) 299 { 300 char[] sa = src.array(); 301 int sp = src.arrayOffset() + src.position(); 302 int sl = src.arrayOffset() + src.limit(); 303 assert (sp <= sl); 304 sp = (sp <= sl ? sp : sl); 305 byte[] da = dst.array(); 306 int dp = dst.arrayOffset() + dst.position(); 307 int dl = dst.arrayOffset() + dst.limit(); 308 assert (dp <= dl); 309 dp = (dp <= dl ? dp : dl); 310 311 int outputSize = 0; 312 byte[] outputByte; 313 int inputSize = 0; // Size of input 314 byte[] tmpBuf = new byte[3]; 315 316 try { 317 while (sp < sl) { 318 outputByte = tmpBuf; 319 char c = sa[sp]; 320 321 if (Character.isSurrogate(c)) { 322 if (sgp.parse(c, sa, sp, sl) < 0) 323 return sgp.error(); 324 return sgp.unmappableResult(); 325 } 326 327 outputSize = encodeSingle(c, outputByte); 328 329 if (outputSize == 0) { // DoubleByte 330 int ncode = encodeDouble(c); 331 if (ncode != 0 ) { 332 if ((ncode & 0xFF0000) == 0) { 333 outputByte[0] = (byte) ((ncode & 0xff00) >> 8); 334 outputByte[1] = (byte) (ncode & 0xff); 335 outputSize = 2; 336 } else { 337 outputByte[0] = (byte) 0x8f; 338 outputByte[1] = (byte) ((ncode & 0xff00) >> 8); 339 outputByte[2] = (byte) (ncode & 0xff); 340 outputSize = 3; 341 } 342 } else { 343 return CoderResult.unmappableForLength(1); 344 } 345 } 346 if (dl - dp < outputSize) 347 return CoderResult.OVERFLOW; 348 // Put the byte in the output buffer 349 for (int i = 0; i < outputSize; i++) { 350 da[dp++] = outputByte[i]; 351 } 352 sp++; 353 } 354 return CoderResult.UNDERFLOW; 355 } finally { 356 src.position(sp - src.arrayOffset()); 357 dst.position(dp - dst.arrayOffset()); 358 } 359 } 360 361 private CoderResult encodeBufferLoop(CharBuffer src, 362 ByteBuffer dst) 363 { 364 int outputSize = 0; 365 byte[] outputByte; 366 int inputSize = 0; // Size of input 367 byte[] tmpBuf = new byte[3]; 368 369 int mark = src.position(); 370 371 try { 372 while (src.hasRemaining()) { 373 outputByte = tmpBuf; 374 char c = src.get(); 375 if (Character.isSurrogate(c)) { 376 if (sgp.parse(c, src) < 0) 377 return sgp.error(); 378 return sgp.unmappableResult(); 379 } 380 381 outputSize = encodeSingle(c, outputByte); 382 if (outputSize == 0) { // DoubleByte 383 int ncode = encodeDouble(c); 384 if (ncode != 0 ) { 385 if ((ncode & 0xFF0000) == 0) { 386 outputByte[0] = (byte) ((ncode & 0xff00) >> 8); 387 outputByte[1] = (byte) (ncode & 0xff); 388 outputSize = 2; 389 } else { 390 outputByte[0] = (byte) 0x8f; 391 outputByte[1] = (byte) ((ncode & 0xff00) >> 8); 392 outputByte[2] = (byte) (ncode & 0xff); 393 outputSize = 3; 394 } 395 } else { 396 return CoderResult.unmappableForLength(1); 397 } 398 } 399 400 if (dst.remaining() < outputSize) 401 return CoderResult.OVERFLOW; 402 // Put the byte in the output buffer 403 for (int i = 0; i < outputSize; i++) { 404 dst.put(outputByte[i]); 405 } 406 mark++; 407 } 408 return CoderResult.UNDERFLOW; 409 } finally { 410 src.position(mark); 411 } 412 } 413 414 protected CoderResult encodeLoop(CharBuffer src, 415 ByteBuffer dst) 416 { 417 if (src.hasArray() && dst.hasArray()) 418 return encodeArrayLoop(src, dst); 419 else 420 return encodeBufferLoop(src, dst); 421 } 422 } 423 }