1 /*
   2  * Copyright (c) 1997, 2001, 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 sun.io;
  27 
  28 /**
  29  * An algorithmic conversion from ISO 2022 to Unicode
  30  *
  31  * @author Tom Zhou
  32  */
  33 public abstract class ByteToCharISO2022 extends ByteToCharConverter
  34 {
  35     // Value to be filled by subclass
  36     protected String SODesignator[];
  37     protected String SS2Designator[] = null;
  38     protected String SS3Designator[] = null;
  39 
  40     protected ByteToCharConverter SOConverter[];
  41     protected ByteToCharConverter SS2Converter[] = null;
  42     protected ByteToCharConverter SS3Converter[] = null;
  43 
  44     private static final byte ISO_ESC = 0x1b;
  45     private static final byte ISO_SI = 0x0f;
  46     private static final byte ISO_SO = 0x0e;
  47     private static final byte ISO_SS2_7 = 0x4e;
  48     private static final byte ISO_SS3_7 = 0x4f;
  49     private static final byte MSB = (byte)0x80;
  50     private static final char REPLACE_CHAR = '\uFFFD';
  51     private static final byte maximumDesignatorLength = 3;
  52 
  53     private static final byte SOFlag = 0;
  54     private static final byte SS2Flag = 1;
  55     private static final byte SS3Flag = 2;
  56     private static final byte G0 = 0;
  57     private static final byte G1 = 1;
  58 
  59     private ByteToCharConverter tmpConverter[];
  60 
  61     private int curSODes, curSS2Des, curSS3Des;
  62     private boolean shiftout;
  63 
  64     private byte remainByte[] = new byte[10];
  65     private int remainIndex = -1;
  66     private byte state, firstByte;
  67 
  68     public void reset()
  69     {
  70         int i = 0;
  71 
  72         shiftout = false;
  73         state = G0;
  74         firstByte = 0;
  75 
  76         curSODes = 0;
  77         curSS2Des = 0;
  78         curSS3Des = 0;
  79 
  80         charOff = byteOff = 0;
  81         remainIndex = -1;
  82 
  83         for(i = 0; i < remainByte.length; i++)
  84             remainByte[i] = 0;
  85     }
  86 
  87     public int flush(char[] output, int outStart, int outEnd)
  88         throws MalformedInputException
  89     {
  90         int i;
  91         if (state != G0) {
  92             badInputLength = 0;
  93             throw new MalformedInputException();
  94         }
  95         reset();
  96         return 0;
  97     }
  98 
  99     private byte[] savetyGetSrc(byte[] input, int inOff, int inEnd, int nbytes)
 100     {
 101         int i;
 102         byte tmp[];
 103 
 104         if(inOff <= (inEnd-nbytes+1))
 105             tmp = new byte[nbytes];
 106         else
 107             tmp = new byte[inEnd-inOff];
 108 
 109         for(i = 0; i < tmp.length; i++)
 110             tmp[i] = input[inOff+i];
 111         return tmp;
 112     }
 113 
 114     private char getUnicode(byte byte1, byte byte2, byte shiftFlag)
 115     {
 116         byte1 |= MSB;
 117         byte2 |= MSB;
 118 
 119         byte[] tmpByte = {byte1,byte2};
 120         char[] tmpChar = new char[1];
 121         int     i = 0,
 122                 tmpIndex = 0;
 123 
 124         switch(shiftFlag) {
 125         case SOFlag:
 126             tmpIndex = curSODes;
 127             tmpConverter = SOConverter;
 128             break;
 129         case SS2Flag:
 130             tmpIndex = curSS2Des;
 131             tmpConverter = SS2Converter;
 132             break;
 133         case SS3Flag:
 134             tmpIndex = curSS3Des;
 135             tmpConverter = SS3Converter;
 136             break;
 137         }
 138 
 139         for(i = 0; i < tmpConverter.length; i++) {
 140             if(tmpIndex == i) {
 141                 try {
 142                     tmpConverter[i].convert(tmpByte, 0, 2, tmpChar, 0, 1);
 143                 } catch (Exception e) {}
 144                 return tmpChar[0];
 145             }
 146         }
 147         return REPLACE_CHAR;
 148     }
 149 
 150     public final int convert(byte[] input, int inOff, int inEnd,
 151                              char[] output, int outOff, int outEnd)
 152                              throws ConversionBufferFullException,
 153                                     MalformedInputException
 154     {
 155         int i;
 156         int DesignatorLength = 0;
 157         charOff  =  outOff;
 158         byteOff  =  inOff;
 159 
 160         // Loop until we hit the end of the input
 161         while (byteOff < inEnd) {
 162             // If we don't have room for the output, throw an exception
 163             if (charOff >= outEnd)
 164                 throw new ConversionBufferFullException();
 165             if(remainIndex < 0) {
 166                 remainByte[0] = input[byteOff];
 167                 remainIndex = 0;
 168                 byteOff++;
 169             }
 170             switch (remainByte[0]) {
 171             case ISO_SO:
 172                 shiftout = true;
 173                 if(remainIndex > 0)
 174                     System.arraycopy(remainByte, 1, remainByte, 0, remainIndex);
 175                 remainIndex--;
 176                 break;
 177             case ISO_SI:
 178                 shiftout = false;
 179                 if(remainIndex > 0)
 180                     System.arraycopy(remainByte, 1, remainByte, 0, remainIndex);
 181                 remainIndex--;
 182                 break;
 183              case ISO_ESC:
 184                 byte tmp[] = savetyGetSrc(input, byteOff, inEnd,
 185                                (maximumDesignatorLength-remainIndex));
 186                 System.arraycopy(tmp, 0, remainByte, remainIndex+1, tmp.length);
 187                 remainIndex += tmp.length;
 188                 byteOff += tmp.length;
 189                 if(tmp.length<(maximumDesignatorLength-remainIndex))
 190                     break;
 191                 String tmpString = new String(remainByte, 1, remainIndex);
 192                 for (i = 0; i < SODesignator.length; i++) {
 193                     if(tmpString.indexOf(SODesignator[i]) == 0) {
 194                         curSODes = i;
 195                         DesignatorLength = SODesignator[i].length();
 196                         break;
 197                     }
 198                 }
 199 
 200                 if (DesignatorLength == 0 ) { // Designator not recognized
 201                    badInputLength = tmp.length;
 202                    throw new MalformedInputException();
 203                 }
 204 
 205                 if (i == SODesignator.length) {
 206                     for (i = 0; i < SS2Designator.length; i++) {
 207                         if(tmpString.indexOf(SS2Designator[i]) == 0) {
 208                             curSS2Des = i;
 209                             DesignatorLength = SS2Designator[i].length();
 210                             break;
 211                         }
 212                     }
 213                     if(i == SS2Designator.length) {
 214                         for(i = 0; i < SS3Designator.length; i++) {
 215                             if (tmpString.indexOf(SS3Designator[i]) == 0) {
 216                                 curSS3Des = i;
 217                                 DesignatorLength = SS3Designator[i].length();
 218                                 break;
 219                             }
 220                         }
 221                         if (i == SS3Designator.length) {
 222                             switch(remainByte[1]) {
 223                             case ISO_SS2_7:
 224                                 output[charOff] = getUnicode(remainByte[2],
 225                                                           remainByte[3],
 226                                                           SS2Flag);
 227                                 charOff++;
 228                                 DesignatorLength = 3;
 229                                 break;
 230                             case ISO_SS3_7:
 231                                 output[charOff] = getUnicode(remainByte[2],
 232                                                           remainByte[3],
 233                                                           SS3Flag);
 234                                 charOff++;
 235                                 DesignatorLength = 3;
 236                                 break;
 237                             default:
 238                                 DesignatorLength = 0;
 239                             }
 240                         }
 241                     }
 242                 }
 243                 if (remainIndex > DesignatorLength) {
 244                     for(i = 0; i < remainIndex-DesignatorLength; i++)
 245                         remainByte[i] = remainByte[DesignatorLength+1+i];
 246                     remainIndex = i-1;
 247                 } else {
 248                     remainIndex = -1;
 249                 }
 250                 break;
 251             default:
 252                 if (!shiftout) {
 253                     output[charOff] = (char)remainByte[0];
 254                     charOff++;
 255                 } else {
 256                     switch (state) {
 257                     case G0:
 258                         firstByte = remainByte[0];
 259                         state = G1;
 260                         break;
 261                     case G1:
 262                         output[charOff] = getUnicode(firstByte, remainByte[0],
 263                                                   SOFlag);
 264                         charOff++;
 265                         state = G0;
 266                         break;
 267                     }
 268                 }
 269                 if (remainIndex > 0)
 270                     System.arraycopy(remainByte, 1, remainByte, 0, remainIndex);
 271                 remainIndex--;
 272             }
 273         }
 274         return charOff - outOff;
 275     }
 276 }