1 /*
   2  * Copyright 1997 Sun Microsystems, Inc.  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.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 package sun.io;
  26 
  27 public abstract class ByteToCharDBCS_EBCDIC extends ByteToCharConverter
  28 {
  29 
  30     private static final int SBCS = 0;
  31     private static final int DBCS = 1;
  32 
  33     private static final int SO = 0x0e;
  34     private static final int SI = 0x0f;
  35 
  36     private int  currentState;
  37     private boolean savedBytePresent;
  38     private byte savedByte;
  39 
  40     protected String singleByteToChar;
  41     protected short index1[];
  42     protected String index2;
  43     protected int   mask1;
  44     protected int   mask2;
  45     protected int   shift;
  46 
  47 
  48     public ByteToCharDBCS_EBCDIC() {
  49        super();
  50        currentState = SBCS;
  51        savedBytePresent = false;
  52     }
  53 
  54     public int flush(char [] output, int outStart, int outEnd)
  55        throws MalformedInputException
  56     {
  57 
  58        if (savedBytePresent) {
  59            reset();
  60            badInputLength = 0;
  61            throw new MalformedInputException();
  62        }
  63 
  64        reset();
  65        return 0;
  66     }
  67 
  68     /**
  69      * Character conversion
  70      */
  71     public int convert(byte[] input, int inOff, int inEnd,
  72                        char[] output, int outOff, int outEnd)
  73         throws UnknownCharacterException, MalformedInputException,
  74                ConversionBufferFullException
  75     {
  76        int  inputSize;
  77        char outputChar = '\uFFFD';
  78 
  79        charOff = outOff;
  80        byteOff = inOff;
  81 
  82        while(byteOff < inEnd) {
  83           int byte1, byte2;
  84           int v;
  85 
  86           if (!savedBytePresent) {
  87             byte1 = input[byteOff];
  88             inputSize = 1;
  89           } else {
  90             byte1 = savedByte;
  91             savedBytePresent = false;
  92             inputSize = 0;
  93           }
  94 
  95           if (byte1 == SO) {
  96 
  97              // For SO characters - simply validate the state and if OK
  98              //    update the state and go to the next byte
  99 
 100              if (currentState != SBCS) {
 101                 badInputLength = 1;
 102                 throw new MalformedInputException();
 103              } else {
 104                 currentState = DBCS;
 105                 byteOff += inputSize;
 106              }
 107           }
 108 
 109           else
 110              if (byte1 == SI) {
 111                 // For SI characters - simply validate the state and if OK
 112                 //    update the state and go to the next byte
 113 
 114                 if (currentState != DBCS) {
 115                    badInputLength = 1;
 116                    throw new MalformedInputException();
 117                 } else {
 118                    currentState = SBCS;
 119                    byteOff+= inputSize;
 120                 }
 121              } else {
 122 
 123                 // Process the real data characters
 124 
 125                 if (byte1 < 0)
 126                    byte1 += 256;
 127 
 128                 if (currentState == SBCS) {
 129                    outputChar = singleByteToChar.charAt(byte1);
 130                 } else {
 131 
 132                    // for a DBCS character - architecture dictates the
 133                    // valid range of 1st bytes
 134 
 135                    if (byte1 < 0x40 || byte1 > 0xfe) {
 136                       badInputLength = 1;
 137                       throw new MalformedInputException();
 138                    }
 139 
 140                    if (byteOff + inputSize >= inEnd) {
 141                       // We have been split in the middle if a character
 142                       // save the first byte for next time around
 143 
 144                       savedByte = (byte)byte1;
 145                       savedBytePresent = true;
 146                       byteOff += inputSize;
 147                       break;
 148                    }
 149 
 150                    byte2 = input[byteOff+inputSize];
 151                    if (byte2 < 0)
 152                       byte2 += 256;
 153 
 154                    inputSize++;
 155 
 156                    // validate the pair of bytes meet the architecture
 157 
 158                    if ((byte1 != 0x40 || byte2 != 0x40) &&
 159                       (byte2 < 0x41 || byte2 > 0xfe)) {
 160                       badInputLength = 2;
 161                       throw new MalformedInputException();
 162                    }
 163 
 164                    // Lookup in the two level index
 165                    v = byte1 * 256 + byte2;
 166                    outputChar = index2.charAt(index1[((v & mask1) >> shift)] + (v & mask2));
 167                 }
 168 
 169                 if (outputChar == '\uFFFD') {
 170                    if (subMode)
 171                       outputChar = subChars[0];
 172                    else {
 173                       badInputLength = inputSize;
 174                       throw new UnknownCharacterException();
 175                    }
 176                 }
 177 
 178                 if (charOff >= outEnd)
 179                    throw new ConversionBufferFullException();
 180 
 181                 output[charOff++] = outputChar;
 182                 byteOff += inputSize;
 183              }
 184 
 185        }
 186 
 187        return charOff - outOff;
 188     }
 189 
 190 
 191     /**
 192      *  Resets the converter.
 193      */
 194     public void reset() {
 195        charOff = byteOff = 0;
 196        currentState = SBCS;
 197        savedBytePresent = false;
 198     }
 199 }