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 import java.nio.*; 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.Surrogate; 36 37 public class EUC_JP_LINUX_OLD 38 extends Charset 39 implements HistoricallyNamedCharset 40 { 41 public EUC_JP_LINUX_OLD() { 42 super("x-euc-jp-linux_OLD", null); 43 } 44 45 public String historicalName() { 46 return "EUC_JP_LINUX"; 47 } 48 49 public boolean contains(Charset cs) { 50 return ((cs instanceof JIS_X_0201_OLD) 51 || (cs.name().equals("US-ASCII")) 52 || (cs instanceof EUC_JP_LINUX_OLD)); 53 } 54 55 public CharsetDecoder newDecoder() { 56 return new Decoder(this); 57 } 58 59 public CharsetEncoder newEncoder() { 60 return new Encoder(this); 61 } 62 63 private static class Decoder extends CharsetDecoder { 64 JIS_X_0201_OLD.Decoder decoderJ0201; 65 protected final char REPLACE_CHAR='\uFFFD'; 66 67 private static final int start = 0xa1; 68 private static final int end = 0xfe; 69 private static final short[] jis0208Index1 = 70 JIS_X_0208_Decoder.getIndex1(); 71 private static final String[] jis0208Index2 = 72 JIS_X_0208_Decoder.getIndex2(); 73 74 private Decoder(Charset cs) { 75 super(cs, 1.0f, 1.0f); 76 decoderJ0201 = new JIS_X_0201_OLD.Decoder(cs); 77 } 78 79 protected char convSingleByte(int b) { 80 if (b < 0 || b > 0x7f) 81 return REPLACE_CHAR; 82 return decoderJ0201.decode(b); 83 } 84 85 protected char decodeDouble(int byte1, int byte2) { 86 if (byte1 == 0x8e) { 87 return decoderJ0201.decode(byte2 - 256); 88 } 89 90 if (((byte1 < 0) || (byte1 > jis0208Index1.length)) 91 || ((byte2 < start) || (byte2 > end))) 92 return REPLACE_CHAR; 93 94 int n = (jis0208Index1[byte1 - 0x80] & 0xf) * (end - start + 1) 95 + (byte2 - start); 96 return jis0208Index2[jis0208Index1[byte1 - 0x80] >> 4].charAt(n); 97 } 98 99 private CoderResult decodeArrayLoop(ByteBuffer src, 100 CharBuffer dst) 101 { 102 byte[] sa = src.array(); 103 int sp = src.arrayOffset() + src.position(); 104 int sl = src.arrayOffset() + src.limit(); 105 assert (sp <= sl); 106 sp = (sp <= sl ? sp : sl); 107 108 char[] da = dst.array(); 109 int dp = dst.arrayOffset() + dst.position(); 110 int dl = dst.arrayOffset() + dst.limit(); 111 assert (dp <= dl); 112 dp = (dp <= dl ? dp : dl); 113 114 int b1 = 0, b2 = 0; 115 int inputSize = 0; 116 char outputChar = REPLACE_CHAR; // U+FFFD; 117 118 try { 119 while (sp < sl) { 120 b1 = sa[sp] & 0xff; 121 inputSize = 1; 122 if ((b1 & 0x80) == 0) { 123 outputChar = (char)b1; 124 } 125 else { // Multibyte char 126 if ((b1 & 0xff) == 0x8f) { // JIS0212 127 if (sp + 3 > sl) 128 return CoderResult.UNDERFLOW; 129 inputSize = 3; 130 return CoderResult.unmappableForLength(inputSize); // substitute 131 } else { 132 // JIS0208 133 if (sp + 2 > sl) 134 return CoderResult.UNDERFLOW; 135 b2 = sa[sp + 1] & 0xff; 136 inputSize = 2; 137 outputChar = decodeDouble(b1, b2); 138 } 139 } 140 if (outputChar == REPLACE_CHAR) { // can't be decoded 141 return CoderResult.unmappableForLength(inputSize); 142 } 143 if (dp + 1 > dl) 144 return CoderResult.OVERFLOW; 145 da[dp++] = outputChar; 146 sp += inputSize; 147 } 148 return CoderResult.UNDERFLOW; 149 } finally { 150 src.position(sp - src.arrayOffset()); 151 dst.position(dp - dst.arrayOffset()); 152 } 153 } 154 155 private CoderResult decodeBufferLoop(ByteBuffer src, 156 CharBuffer dst) 157 { 158 int mark = src.position(); 159 char outputChar = REPLACE_CHAR; // U+FFFD; 160 161 try { 162 while (src.hasRemaining()) { 163 int b1 = src.get() & 0xff; 164 int inputSize = 1; 165 166 if ((b1 & 0x80) == 0) { 167 outputChar = (char)b1; 168 } else { // Multibyte char 169 170 if ((b1 & 0xff) == 0x8f) { // JIS0212 not supported 171 if (src.remaining() < 2) 172 return CoderResult.UNDERFLOW; 173 return CoderResult.unmappableForLength(3); 174 } else { 175 // JIS0208 176 if (src.remaining() < 1) 177 return CoderResult.UNDERFLOW; 178 int b2 = src.get() & 0xff; 179 inputSize++; 180 outputChar = decodeDouble(b1, b2); 181 } 182 } 183 184 if (outputChar == REPLACE_CHAR) 185 return CoderResult.unmappableForLength(inputSize); 186 if (dst.remaining() < 1) 187 return CoderResult.OVERFLOW; 188 dst.put(outputChar); 189 mark += inputSize; 190 } 191 return CoderResult.UNDERFLOW; 192 } finally { 193 src.position(mark); 194 } 195 } 196 197 protected CoderResult decodeLoop(ByteBuffer src, 198 CharBuffer dst) 199 { 200 if (src.hasArray() && dst.hasArray()) 201 return decodeArrayLoop(src, dst); 202 else 203 return decodeBufferLoop(src, dst); 204 } 205 } 206 207 208 private static class Encoder extends CharsetEncoder { 209 210 JIS_X_0201_OLD.Encoder encoderJ0201; 211 212 private final Surrogate.Parser sgp = new Surrogate.Parser(); 213 private static final short[] jis0208Index1 = 214 JIS_X_0208_Encoder.getIndex1(); 215 private static final String[] jis0208Index2 = 216 JIS_X_0208_Encoder.getIndex2(); 217 218 private Encoder(Charset cs) { 219 super(cs, 2.0f, 2.0f); 220 encoderJ0201 = new JIS_X_0201_OLD.Encoder(cs); 221 } 222 223 public boolean canEncode(char c) { 224 byte[] encodedBytes = new byte[2]; 225 226 if (encodeSingle(c, encodedBytes) == 0) { //doublebyte 227 if (encodeDouble(c) == 0) 228 return false; 229 } 230 return true; 231 } 232 233 protected int encodeSingle(char inputChar, byte[] outputByte) { 234 byte b; 235 236 if (inputChar == 0) { 237 outputByte[0] = (byte)0; 238 return 1; 239 } 240 241 if ((b = encoderJ0201.encode(inputChar)) == 0) 242 return 0; 243 244 if (b > 0 && b < 128) { 245 outputByte[0] = b; 246 return 1; 247 } 248 outputByte[0] = (byte)0x8e; 249 outputByte[1] = b; 250 return 2; 251 } 252 253 protected int encodeDouble(char ch) { 254 int offset = jis0208Index1[((ch & 0xff00) >> 8 )] << 8; 255 int r = jis0208Index2[offset >> 12].charAt((offset & 0xfff) + (ch & 0xff)); 256 if (r != 0) 257 return r + 0x8080; 258 return r; 259 } 260 261 private CoderResult encodeArrayLoop(CharBuffer src, 262 ByteBuffer dst) 263 { 264 char[] sa = src.array(); 265 int sp = src.arrayOffset() + src.position(); 266 int sl = src.arrayOffset() + src.limit(); 267 assert (sp <= sl); 268 sp = (sp <= sl ? sp : sl); 269 byte[] da = dst.array(); 270 int dp = dst.arrayOffset() + dst.position(); 271 int dl = dst.arrayOffset() + dst.limit(); 272 assert (dp <= dl); 273 dp = (dp <= dl ? dp : dl); 274 275 final byte[] outputByte = new byte[2]; 276 277 try { 278 while (sp < sl) { 279 char c = sa[sp]; 280 281 if (Character.isSurrogate(c)) { 282 if (sgp.parse(c, sa, sp, sl) < 0) 283 return sgp.error(); 284 return sgp.unmappableResult(); 285 } 286 287 int outputSize = encodeSingle(c, outputByte); 288 if (outputSize == 0) { // DoubleByte 289 int ncode = encodeDouble(c); 290 if (ncode != 0 && ((ncode & 0xFF0000) == 0)) { 291 outputByte[0] = (byte) ((ncode & 0xff00) >> 8); 292 outputByte[1] = (byte) (ncode & 0xff); 293 outputSize = 2; 294 } else { 295 return CoderResult.unmappableForLength(1); 296 } 297 } 298 299 if (dl - dp < outputSize) 300 return CoderResult.OVERFLOW; 301 // Put the byte in the output buffer 302 for (int i = 0; i < outputSize; i++) { 303 da[dp++] = outputByte[i]; 304 } 305 sp++; 306 } 307 return CoderResult.UNDERFLOW; 308 } finally { 309 src.position(sp - src.arrayOffset()); 310 dst.position(dp - dst.arrayOffset()); 311 } 312 } 313 314 private CoderResult encodeBufferLoop(CharBuffer src, 315 ByteBuffer dst) 316 { 317 final byte[] outputByte = new byte[4]; 318 int mark = src.position(); 319 320 try { 321 while (src.hasRemaining()) { 322 char c = src.get(); 323 if (Character.isSurrogate(c)) { 324 if (sgp.parse(c, src) < 0) 325 return sgp.error(); 326 return sgp.unmappableResult(); 327 } 328 329 int outputSize = encodeSingle(c, outputByte); 330 if (outputSize == 0) { // DoubleByte 331 int ncode = encodeDouble(c); 332 if (ncode != 0 ) { 333 if ((ncode & 0xFF0000) == 0) { 334 outputByte[0] = (byte) ((ncode & 0xff00) >> 8); 335 outputByte[1] = (byte) (ncode & 0xff); 336 outputSize = 2; 337 } 338 } else { 339 return CoderResult.unmappableForLength(1); 340 } 341 } 342 343 if (dst.remaining() < outputSize) 344 return CoderResult.OVERFLOW; 345 346 // Put the byte in the output buffer 347 for (int i = 0; i < outputSize; i++) { 348 dst.put(outputByte[i]); 349 } 350 mark++; 351 } 352 return CoderResult.UNDERFLOW; 353 } finally { 354 src.position(mark); 355 } 356 } 357 358 protected CoderResult encodeLoop(CharBuffer src, 359 ByteBuffer dst) 360 { 361 if (src.hasArray() && dst.hasArray()) 362 return encodeArrayLoop(src, dst); 363 else 364 return encodeBufferLoop(src, dst); 365 } 366 } 367 }