1 /*
   2  * Copyright 1996-2003 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 
  26 package sun.io;
  27 
  28 import sun.nio.cs.ext.EUC_TW;
  29 
  30 /*
  31  * @author Limin Shi
  32  */
  33 
  34 public class CharToByteEUC_TW extends CharToByteConverter
  35 {
  36     private final byte MSB = (byte)0x80;
  37     private final byte SS2 = (byte) 0x8E;
  38     private final byte P2 = (byte) 0xA2;
  39     private final byte P3 = (byte) 0xA3;
  40 
  41     private final static EUC_TW nioCoder = new EUC_TW();
  42 
  43     private static String uniTab1 = nioCoder.getUniTab1();
  44     private static String uniTab2 = nioCoder.getUniTab2();
  45     private static String uniTab3 = nioCoder.getUniTab3();
  46     private static String cnsTab1 = nioCoder.getCNSTab1();
  47     private static String cnsTab2 = nioCoder.getCNSTab2();
  48     private static String cnsTab3 = nioCoder.getCNSTab3();
  49 
  50     public int flush(byte[] output, int outStart, int outEnd)
  51         throws MalformedInputException
  52     {
  53         reset();
  54         return 0;
  55     }
  56 
  57     public void reset() {
  58         byteOff = charOff = 0;
  59     }
  60 
  61     public boolean canConvert(char ch){
  62         if (((0xFF00 & ch) != 0) && (getNative(ch) != -1)){
  63             return true;
  64         }
  65         return false;
  66     }
  67 
  68     /**
  69      * Character conversion
  70      */
  71     public int convert(char[] input, int inOff, int inEnd,
  72                        byte[] output, int outOff, int outEnd)
  73         throws UnknownCharacterException, MalformedInputException,
  74                ConversionBufferFullException
  75     {
  76         int outputSize;
  77         byte [] tmpbuf = new byte[4];
  78         byte [] outputByte;
  79 
  80         byteOff = outOff;
  81 
  82         //Fixed 4122961 by bringing the charOff++ out to this
  83         // loop where it belongs, changing the loop from
  84         // while(){} to for(){}.
  85         for (charOff = inOff; charOff < inEnd; charOff++) {
  86             outputByte = tmpbuf;
  87             if ( input[charOff] < 0x80) {       // ASCII
  88                 outputSize = 1;
  89                 outputByte[0] = (byte)(input[charOff] & 0x7f);
  90             } else {
  91                 outputSize = unicodeToEUC(input[charOff], outputByte);
  92             }
  93 
  94             if (outputSize == -1) {
  95                 if (subMode) {
  96                     outputByte = subBytes;
  97                     outputSize = subBytes.length;
  98                 } else {
  99                     badInputLength = 1;
 100                     throw new UnknownCharacterException();
 101                 }
 102             }
 103 
 104             if (outEnd - byteOff < outputSize)
 105                 throw new ConversionBufferFullException();
 106 
 107             for (int i = 0; i < outputSize; i++)
 108                 output[byteOff++] = outputByte[i];
 109         }
 110 
 111         return byteOff - outOff;
 112 
 113     }
 114 
 115 
 116     /**
 117      * returns the maximum number of bytes needed to convert a char
 118      */
 119     public int getMaxBytesPerChar() {
 120         return 4;
 121     }
 122 
 123 
 124     /**
 125      * Return the character set ID
 126      */
 127     public String getCharacterEncoding() {
 128         return "EUC_TW";
 129     }
 130 
 131 
 132     protected int getNative(char unicode) {
 133         int  i,
 134              cns;       // 2 chars in CNS table make 1 CNS code
 135 
 136         if (unicode < UniTab2[0]) {
 137             if ((i = searchTab(unicode, UniTab1)) == -1)
 138                 return -1;
 139             cns = (CNSTab1[2*i] << 16) + CNSTab1[2*i+1];
 140             return cns;
 141         } else  if (unicode < UniTab3[0]) {
 142             if ((i = searchTab(unicode, UniTab2)) == -1)
 143                 return -1;
 144             cns = (CNSTab2[2*i] << 16) + CNSTab2[2*i+1];
 145             return cns;
 146         } else {
 147             if ((i = searchTab(unicode, UniTab3)) == -1)
 148                 return -1;
 149             cns = (CNSTab3[2*i] << 16) + CNSTab3[2*i+1];
 150             return cns;
 151         }
 152     }
 153 
 154     protected int searchTab(char code, char [] table) {
 155         int     i = 0, l, h;
 156 
 157         for (l = 0, h = table.length - 1; l < h; ) {
 158                 if (table[l] == code) {
 159                         i = l;
 160                         break;
 161                 }
 162                 if (table[h] == code) {
 163                         i = h;
 164                         break;
 165                 }
 166                 i = (l + h) / 2;
 167                 if (table[i] == code)
 168                         break;
 169                 if (table[i] < code)
 170                         l = i + 1;
 171                 else    h = i - 1;
 172         }
 173         if (code == table[i]) {
 174             return i;
 175         } else {
 176             return -1;
 177         }
 178     }
 179 
 180 
 181     private int unicodeToEUC(char unicode, byte ebyte[]) {
 182         int cns = getNative(unicode);
 183 
 184         if ((cns >> 16) == 0x01) {      // Plane 1
 185             ebyte[0] = (byte) (((cns & 0xff00) >> 8) | MSB);
 186             ebyte[1] = (byte) ((cns & 0xff) | MSB);
 187             return 2;
 188         }
 189 
 190         byte cnsPlane = (byte)(cns >> 16);
 191         if (cnsPlane >= (byte)0x02) {   // Plane 2
 192             ebyte[0] = SS2;
 193             ebyte[1] = (byte) (cnsPlane | (byte)0xA0);
 194             ebyte[2] = (byte) (((cns & 0xff00) >> 8) | MSB);
 195             ebyte[3] = (byte) ((cns & 0xff) | MSB);
 196             return 4;
 197         }
 198 
 199         return -1;
 200     }
 201 
 202     protected int unicodeToEUC(char unicode) {
 203         if (unicode <= 0x7F) { // ASCII falls into EUC_TW CS0
 204             return unicode;
 205         }
 206 
 207         int cns = getNative(unicode);
 208         int plane = cns >> 16;
 209         int euc = (cns & 0x0000FFFF) | 0x00008080;
 210 
 211         if (plane == 1) {
 212             return euc;
 213         } else if (plane == 2) {
 214             return ((SS2 << 24) & 0xFF000000) | ((P2 << 16) & 0x00FF0000) |
 215                 euc;
 216         } else if (plane == 3) {
 217             return ((SS2 << 24) & 0xFF000000) | ((P3 << 16) & 0x00FF0000) |
 218                 euc;
 219         }
 220 
 221         return -1;
 222     }
 223 
 224     private char [] UniTab1 = uniTab1.toCharArray();
 225     private char [] UniTab2 = uniTab2.toCharArray();
 226     private char [] UniTab3 = uniTab3.toCharArray();
 227     private char [] CNSTab1 = cnsTab1.toCharArray();
 228     private char [] CNSTab2 = cnsTab2.toCharArray();
 229     private char [] CNSTab3 = cnsTab3.toCharArray();
 230 }