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