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