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.Surrogate;
  28 import sun.nio.cs.ext.DoubleByte;
  29 import static sun.nio.cs.CharsetMapping.*;
  30 
  31 public abstract class CharToByteDBCS_ASCII extends CharToByteConverter
  32 {
  33 
  34     private char highHalfZoneCode;
  35     private byte[] outputByte = new byte[2];
  36 
  37     private DoubleByte.Encoder enc;
  38 
  39     public CharToByteDBCS_ASCII(DoubleByte.Encoder enc) {
  40         super();
  41         this.enc = enc;
  42     }
  43 
  44     int encodeChar(char c) {
  45         return enc.encodeChar(c);
  46     }
  47 
  48     /**
  49       * flush out any residual data and reset the buffer state
  50       */
  51     public int flush(byte [] output, int outStart, int outEnd)
  52         throws MalformedInputException, ConversionBufferFullException
  53     {
  54 
  55        if (highHalfZoneCode != 0) {
  56           reset();
  57           badInputLength = 0;
  58           throw new MalformedInputException();
  59        }
  60 
  61        reset();
  62        return 0;
  63     }
  64 
  65     /**
  66      * Character conversion
  67      */
  68     public int convert(char[] input, int inOff, int inEnd,
  69                        byte[] output, int outOff, int outEnd)
  70         throws UnknownCharacterException, MalformedInputException,
  71                ConversionBufferFullException
  72     {
  73         char    inputChar;
  74         int     inputSize;
  75 
  76         byteOff = outOff;
  77         charOff = inOff;
  78 
  79         while(charOff < inEnd) {
  80             int   index;
  81             int   theBytes;
  82             int   spaceNeeded;
  83 
  84             if (highHalfZoneCode == 0) {
  85                 inputChar = input[charOff];
  86                 inputSize = 1;
  87             } else {
  88                 inputChar = highHalfZoneCode;
  89                 inputSize = 0;
  90                 highHalfZoneCode = 0;
  91             }
  92 
  93             // Is this a high surrogate?
  94             if (Surrogate.isHigh(inputChar)) {
  95                 // Is this the last character of the input?
  96                 if (charOff + inputSize >= inEnd) {
  97                     highHalfZoneCode = inputChar;
  98                     charOff += inputSize;
  99                     break;
 100                 }
 101 
 102                 // Is there a low surrogate following?
 103                 inputChar = input[charOff + inputSize];
 104                 if (Surrogate.isLow(inputChar)) {
 105                     // We have a valid surrogate pair.  Too bad we don't do
 106                     // surrogates.  Is substitution enabled?
 107                     if (subMode) {
 108                         if (subBytes.length == 1) {
 109                             outputByte[0] = 0x00;
 110                             outputByte[1] = subBytes[0];
 111                         }
 112                         else {
 113                             outputByte[0] = subBytes[0];
 114                             outputByte[1] = subBytes[1];
 115                         }
 116                         inputSize++;
 117                     } else {
 118                         badInputLength = 2;
 119                         throw new UnknownCharacterException();
 120                     }
 121                  } else {
 122                      // We have a malformed surrogate pair
 123                      badInputLength = 1;
 124                      throw new MalformedInputException();
 125                  }
 126             }
 127             // Is this an unaccompanied low surrogate?
 128             else if (Surrogate.isLow(inputChar)) {
 129                 badInputLength = 1;
 130                 throw new MalformedInputException();
 131             } else {
 132 
 133                 // We have a valid character, get the bytes for it
 134                 theBytes = encodeChar(inputChar);
 135                 if (theBytes == UNMAPPABLE_ENCODING) {
 136                     // if there was no mapping - look for substitution characters
 137                     if (subMode) {
 138                         if (subBytes.length == 1) {
 139                             outputByte[0] = 0x00;
 140                             outputByte[1] = subBytes[0];
 141                         } else {
 142                             outputByte[0] = subBytes[0];
 143                             outputByte[1] = subBytes[1];
 144                         }
 145                     } else {
 146                         badInputLength = 1;
 147                         throw new UnknownCharacterException();
 148                     }
 149                 } else {
 150                     outputByte[0] = (byte)(theBytes >>8);
 151                     outputByte[1] = (byte)theBytes;
 152                 }
 153             }
 154             if (outputByte[0] == 0x00)
 155                 spaceNeeded = 1;
 156             else
 157                 spaceNeeded = 2;
 158 
 159             if (byteOff + spaceNeeded > outEnd)
 160                 throw new ConversionBufferFullException();
 161 
 162             if (spaceNeeded == 1)
 163                 output[byteOff++] = outputByte[1];
 164             else {
 165                 output[byteOff++] = outputByte[0];
 166                 output[byteOff++] = outputByte[1];
 167             }
 168 
 169             charOff += inputSize;
 170         }
 171         return byteOff - outOff;
 172     }
 173 
 174     /**
 175      * Resets converter to its initial state.
 176      */
 177     public void reset() {
 178        charOff = byteOff = 0;
 179        highHalfZoneCode = 0;
 180     }
 181 
 182     /**
 183      * Returns the maximum number of bytes needed to convert a char.
 184      */
 185     public int getMaxBytesPerChar() {
 186         return 2;
 187     }
 188 
 189     /**
 190      * Returns true if the given character can be converted to the
 191      * target character encoding.
 192      */
 193     public boolean canConvert(char c) {
 194         return encodeChar(c) != UNMAPPABLE_ENCODING;    
 195     }
 196 }