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 }