1 /*
   2  * Copyright 2003-2006 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 /*
  27  */
  28 
  29 
  30 import java.nio.ByteBuffer;
  31 import java.nio.CharBuffer;
  32 import java.nio.charset.Charset;
  33 import java.nio.charset.CharsetEncoder;
  34 import java.nio.charset.CoderResult;
  35 import sun.nio.cs.Surrogate;
  36 
  37 /**
  38  * An abstract base class for subclasses which encodes
  39  * IBM double byte host encodings such as ibm code
  40  * pages 942,943,948, etc.
  41  *
  42  */
  43 
  44 public abstract class DBCS_IBM_EBCDIC_Encoder extends CharsetEncoder
  45 {
  46 
  47     protected static final char REPLACE_CHAR='\uFFFD';
  48     private byte b1;
  49     private byte b2;
  50 
  51     protected short index1[];
  52     protected String index2;
  53     protected String index2a;
  54     protected int   mask1;
  55     protected int   mask2;
  56     protected int   shift;
  57 
  58     private static final int SBCS = 0;
  59     private static final int DBCS = 1;
  60 
  61     private static final byte SO = 0x0e;
  62     private static final byte SI = 0x0f;
  63 
  64     private int  currentState;
  65 
  66     private final Surrogate.Parser sgp = new Surrogate.Parser();
  67 
  68     protected DBCS_IBM_EBCDIC_Encoder(Charset cs) {
  69         super(cs, 4.0f, 5.0f, new byte[] {(byte)0x6f});
  70     }
  71 
  72     protected void implReset() {
  73         currentState = SBCS;
  74     }
  75 
  76     protected CoderResult implFlush(ByteBuffer out) {
  77         if (currentState == DBCS) {
  78             if (out.remaining() < 1)
  79                 return CoderResult.OVERFLOW;
  80             out.put(SI);
  81         }
  82         implReset();
  83         return CoderResult.UNDERFLOW;
  84     }
  85 
  86     /**
  87      * Returns true if the given character can be converted to the
  88      * target character encoding.
  89      */
  90     public boolean canEncode(char ch) {
  91        int  index;
  92        int  theBytes;
  93 
  94        index = index1[((ch & mask1) >> shift)] + (ch & mask2);
  95        if (index  < 15000)
  96          theBytes = (int)(index2.charAt(index));
  97        else
  98          theBytes = (int)(index2a.charAt(index-15000));
  99 
 100        if (theBytes != 0)
 101          return (true);
 102 
 103        // only return true if input char was unicode null - all others are
 104        //     undefined
 105        return( ch == '\u0000');
 106 
 107     }
 108 
 109     private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
 110         char[] sa = src.array();
 111         int sp = src.arrayOffset() + src.position();
 112         int sl = src.arrayOffset() + src.limit();
 113         byte[] da = dst.array();
 114         int dp = dst.arrayOffset() + dst.position();
 115         int dl = dst.arrayOffset() + dst.limit();
 116         int outputSize = 0;             // size of output
 117         int spaceNeeded;
 118 
 119         try {
 120             while (sp < sl) {
 121                 int index;
 122                 int theBytes;
 123                 char c = sa[sp];
 124                 if (Surrogate.is(c)) {
 125                     if (sgp.parse(c, sa, sp, sl) < 0)
 126                         return sgp.error();
 127                     return sgp.unmappableResult();
 128                 }
 129                 if (c >= '\uFFFE')
 130                     return CoderResult.unmappableForLength(1);
 131 
 132 
 133                 index = index1[((c & mask1) >> shift)]
 134                                 + (c & mask2);
 135                 if (index < 15000)
 136                     theBytes = (int)(index2.charAt(index));
 137                 else
 138                     theBytes = (int)(index2a.charAt(index-15000));
 139                 b1= (byte)((theBytes & 0x0000ff00)>>8);
 140                 b2 = (byte)(theBytes & 0x000000ff);
 141 
 142                 if (b1 == 0x00 && b2 == 0x00
 143                     && c != '\u0000') {
 144                         return CoderResult.unmappableForLength(1);
 145                 }
 146 
 147                 if (currentState == DBCS && b1 == 0x00) {
 148                     if (dl - dp < 1)
 149                         return CoderResult.OVERFLOW;
 150                     currentState = SBCS;
 151                     da[dp++] = SI;
 152                 } else if (currentState == SBCS && b1 != 0x00) {
 153                     if (dl - dp < 1)
 154                         return CoderResult.OVERFLOW;
 155                     currentState = DBCS;
 156                     da[dp++] = SO;
 157                 }
 158                 if (currentState == DBCS)
 159                     spaceNeeded = 2;
 160                 else
 161                     spaceNeeded = 1;
 162                 if (dl - dp < spaceNeeded)
 163                     return CoderResult.OVERFLOW;
 164 
 165                 if (currentState == SBCS)
 166                     da[dp++] = b2;
 167                 else {
 168                     da[dp++] = b1;
 169                     da[dp++] = b2;
 170                 }
 171                 sp++;
 172             }
 173             return CoderResult.UNDERFLOW;
 174         } finally {
 175             src.position(sp - src.arrayOffset());
 176             dst.position(dp - dst.arrayOffset());
 177         }
 178     }
 179 
 180     private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
 181         int mark = src.position();
 182         int outputSize = 0;             // size of output
 183         int spaceNeeded;
 184 
 185         try {
 186             while (src.hasRemaining()) {
 187                 int index;
 188                 int theBytes;
 189                 char c = src.get();
 190                 if (Surrogate.is(c)) {
 191                     if (sgp.parse(c, src) < 0)
 192                         return sgp.error();
 193                     return sgp.unmappableResult();
 194                 }
 195                 if (c >= '\uFFFE')
 196                     return CoderResult.unmappableForLength(1);
 197 
 198                 index = index1[((c & mask1) >> shift)]
 199                                 + (c & mask2);
 200                 if (index < 15000)
 201                     theBytes = (int)(index2.charAt(index));
 202                 else
 203                     theBytes = (int)(index2a.charAt(index-15000));
 204                 b1 = (byte)((theBytes & 0x0000ff00)>>8);
 205                 b2 = (byte)(theBytes & 0x000000ff);
 206 
 207                 if (b1== 0x00 && b2 == 0x00
 208                     && c != '\u0000') {
 209                         return CoderResult.unmappableForLength(1);
 210                 }
 211 
 212                 if (currentState == DBCS && b1 == 0x00) {
 213                     if (dst.remaining() < 1)
 214                         return CoderResult.OVERFLOW;
 215                     currentState = SBCS;
 216                     dst.put(SI);
 217                 } else if (currentState == SBCS && b1 != 0x00) {
 218                     if (dst.remaining() < 1)
 219                         return CoderResult.OVERFLOW;
 220                     currentState = DBCS;
 221                     dst.put(SO);
 222                 }
 223 
 224                 if (currentState == DBCS)
 225                     spaceNeeded = 2;
 226                 else
 227                     spaceNeeded = 1;
 228 
 229                 if (dst.remaining() < spaceNeeded)
 230                     return CoderResult.OVERFLOW;
 231 
 232                 if (currentState == SBCS)
 233                     dst.put(b2);
 234                 else {
 235                     dst.put(b1);
 236                     dst.put(b2);
 237                 }
 238                 mark++;
 239              }
 240             return CoderResult.UNDERFLOW;
 241         } finally {
 242             src.position(mark);
 243         }
 244     }
 245 
 246     protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
 247         if (true && src.hasArray() && dst.hasArray())
 248             return encodeArrayLoop(src, dst);
 249         else
 250             return encodeBufferLoop(src, dst);
 251     }
 252 
 253 }