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 import sun.nio.cs.ext.DoubleByte;
  28 import static sun.nio.cs.CharsetMapping.*;
  29 
  30 public abstract class ByteToCharDBCS_EBCDIC extends ByteToCharConverter
  31 {
  32 
  33     private static final int SBCS = 0;
  34     private static final int DBCS = 1;
  35 
  36     private static final int SO = 0x0e;
  37     private static final int SI = 0x0f;
  38 
  39     private int  currentState;
  40     private boolean savedBytePresent;
  41     private int savedByte;
  42 
  43     private DoubleByte.Decoder dec;
  44 
  45     public ByteToCharDBCS_EBCDIC(DoubleByte.Decoder dec) {
  46        super();
  47        currentState = SBCS;
  48        savedBytePresent = false;
  49        this.dec = dec;
  50     }
  51 
  52     char decodeSingle(int b) {
  53         return dec.decodeSingle(b);
  54     }
  55 
  56     char decodeDouble(int b1, int b2) {
  57         return dec.decodeDouble(b1, b2);
  58     }
  59 
  60     public int flush(char [] output, int outStart, int outEnd)
  61        throws MalformedInputException
  62     {
  63 
  64        if (savedBytePresent) {
  65            reset();
  66            badInputLength = 0;
  67            throw new MalformedInputException();
  68        }
  69 
  70        reset();
  71        return 0;
  72     }
  73 
  74     /**
  75      * Character conversion
  76      */
  77     public int convert(byte[] input, int inOff, int inEnd,
  78                        char[] output, int outOff, int outEnd)
  79         throws UnknownCharacterException, MalformedInputException,
  80                ConversionBufferFullException
  81     {
  82        int  inputSize;
  83        char outputChar = UNMAPPABLE_DECODING;
  84 
  85        charOff = outOff;
  86        byteOff = inOff;
  87 
  88        while(byteOff < inEnd) {
  89           int byte1, byte2;
  90 
  91           if (!savedBytePresent) {
  92             byte1 = input[byteOff] & 0xff;
  93             inputSize = 1;
  94           } else {
  95             byte1 = savedByte;
  96             savedBytePresent = false;
  97             inputSize = 0;
  98           }
  99 
 100           if (byte1 == SO) {
 101 
 102              // For SO characters - simply validate the state and if OK
 103              //    update the state and go to the next byte
 104 
 105              if (currentState != SBCS) {
 106                 badInputLength = 1;
 107                 throw new MalformedInputException();
 108              } else {
 109                 currentState = DBCS;
 110                 byteOff += inputSize;
 111              }
 112           }
 113 
 114           else
 115              if (byte1 == SI) {
 116                 // For SI characters - simply validate the state and if OK
 117                 //    update the state and go to the next byte
 118 
 119                 if (currentState != DBCS) {
 120                    badInputLength = 1;
 121                    throw new MalformedInputException();
 122                 } else {
 123                    currentState = SBCS;
 124                    byteOff+= inputSize;
 125                 }
 126              } else {
 127 
 128                 // Process the real data characters
 129 
 130                 if (currentState == SBCS) {
 131                    outputChar = decodeSingle(byte1);
 132                 } else {
 133 
 134                    // for a DBCS character - architecture dictates the
 135                    // valid range of 1st bytes
 136 
 137                    if (byte1 < 0x40 || byte1 > 0xfe) {
 138                       badInputLength = 1;
 139                       throw new MalformedInputException();
 140                    }
 141 
 142                    if (byteOff + inputSize >= inEnd) {
 143                       // We have been split in the middle if a character
 144                       // save the first byte for next time around
 145 
 146                       savedByte = byte1;
 147                       savedBytePresent = true;
 148                       byteOff += inputSize;
 149                       break;
 150                    }
 151 
 152                    byte2 = input[byteOff+inputSize] & 0xff;
 153                    inputSize++;
 154 
 155                    // validate the pair of bytes meet the architecture
 156 
 157                    if ((byte1 != 0x40 || byte2 != 0x40) &&
 158                       (byte2 < 0x41 || byte2 > 0xfe)) {
 159                       badInputLength = 2;
 160                       throw new MalformedInputException();
 161                    }
 162 
 163                    outputChar = decodeDouble(byte1, byte2);
 164                 }
 165 
 166                 if (outputChar == UNMAPPABLE_DECODING) {
 167                    if (subMode)
 168                       outputChar = subChars[0];
 169                    else {
 170                       badInputLength = inputSize;
 171                       throw new UnknownCharacterException();
 172                    }
 173                 }
 174 
 175                 if (charOff >= outEnd)
 176                    throw new ConversionBufferFullException();
 177 
 178                 output[charOff++] = outputChar;
 179                 byteOff += inputSize;
 180              }
 181 
 182        }
 183 
 184        return charOff - outOff;
 185     }
 186 
 187 
 188     /**
 189      *  Resets the converter.
 190      */
 191     public void reset() {
 192        charOff = byteOff = 0;
 193        currentState = SBCS;
 194        savedBytePresent = false;
 195     }
 196 }