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 abstract class DBCS_IBM_ASCII_Encoder extends CharsetEncoder
  45 {
  46 
  47     protected static final char REPLACE_CHAR='\uFFFD';
  48     private byte b1;
  49     private byte b2;
  50 
  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 final Surrogate.Parser sgp = new Surrogate.Parser();
  60 
  61     protected DBCS_IBM_ASCII_Encoder(Charset cs) {
  62         super(cs, 2.0f, 2.0f);
  63     }
  64 
  65     /**
  66      * Returns true if the given character can be converted to the
  67      * target character encoding.
  68      */
  69     public boolean canEncode(char ch) {
  70        int  index;
  71        int  theBytes;
  72 
  73        index = index1[((ch & mask1) >> shift)] + (ch & mask2);
  74        if (index < 15000)
  75          theBytes = (int)(index2.charAt(index));
  76        else
  77          theBytes = (int)(index2a.charAt(index-15000));
  78 
  79        if (theBytes != 0)
  80          return (true);
  81 
  82        // only return true if input char was unicode null - all others are
  83        //     undefined
  84        return( ch == '\u0000');
  85 
  86     }
  87 
  88     private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
  89         char[] sa = src.array();
  90         int sp = src.arrayOffset() + src.position();
  91         int sl = src.arrayOffset() + src.limit();
  92         byte[] da = dst.array();
  93         int dp = dst.arrayOffset() + dst.position();
  94         int dl = dst.arrayOffset() + dst.limit();
  95         int outputSize = 0;             // size of output
  96 
  97         try {
  98             while (sp < sl) {
  99                 int index;
 100                 int theBytes;
 101                 char c = sa[sp];
 102                 if (Surrogate.is(c)) {
 103                     if (sgp.parse(c, sa, sp, sl) < 0)
 104                         return sgp.error();
 105                     return sgp.unmappableResult();
 106                 }
 107                 if (c >= '\uFFFE')
 108                     return CoderResult.unmappableForLength(1);
 109 
 110                 index = index1[((c & mask1) >> shift)]
 111                                 + (c & mask2);
 112                 if (index < 15000)
 113                     theBytes = (int)(index2.charAt(index));
 114                 else
 115                     theBytes = (int)(index2a.charAt(index-15000));
 116                 b1 = (byte)((theBytes & 0x0000ff00)>>8);
 117                 b2 = (byte)(theBytes & 0x000000ff);
 118 
 119                 if (b1 == 0x00 && b2 == 0x00
 120                     && c != '\u0000') {
 121                         return CoderResult.unmappableForLength(1);
 122                 }
 123 
 124                 if (b1 == 0) {
 125                     if (dl - dp < 1)
 126                         return CoderResult.OVERFLOW;
 127                     da[dp++] = (byte) b2;
 128                 } else {
 129                     if (dl - dp < 2)
 130                         return CoderResult.OVERFLOW;
 131                     da[dp++] = (byte) b1;
 132                     da[dp++] = (byte) b2;
 133                 }
 134                 sp++;
 135             }
 136             return CoderResult.UNDERFLOW;
 137         } finally {
 138             src.position(sp - src.arrayOffset());
 139             dst.position(dp - dst.arrayOffset());
 140         }
 141     }
 142 
 143     private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
 144         int mark = src.position();
 145         int outputSize = 0;             // size of output
 146 
 147         try {
 148             while (src.hasRemaining()) {
 149                 int index;
 150                 int theBytes;
 151                 char c = src.get();
 152                 if (Surrogate.is(c)) {
 153                     if (sgp.parse(c, src) < 0)
 154                         return sgp.error();
 155                     return sgp.unmappableResult();
 156                 }
 157                 if (c >= '\uFFFE')
 158                     return CoderResult.unmappableForLength(1);
 159 
 160                 index = index1[((c & mask1) >> shift)]
 161                                 + (c & mask2);
 162                 if (index < 15000)
 163                     theBytes = (int)(index2.charAt(index));
 164                 else
 165                     theBytes = (int)(index2a.charAt(index-15000));
 166                 b1 = (byte)((theBytes & 0x0000ff00)>>8);
 167                 b2 = (byte)(theBytes & 0x000000ff);
 168 
 169                 if (b1 == 0x00 && b2 == 0x00
 170                     && c != '\u0000') {
 171                         return CoderResult.unmappableForLength(1);
 172                 }
 173 
 174                 if (b1 == 0) {
 175                     if (dst.remaining() < 1)
 176                         return CoderResult.OVERFLOW;
 177                     dst.put((byte) b2);
 178                 } else {
 179                     if (dst.remaining() < 2)
 180                         return CoderResult.OVERFLOW;
 181                     dst.put((byte) b1);
 182                     dst.put((byte) b2);
 183                 }
 184                 mark++;
 185              }
 186             return CoderResult.UNDERFLOW;
 187         } finally {
 188             src.position(mark);
 189         }
 190     }
 191 
 192     protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
 193         if (true && src.hasArray() && dst.hasArray())
 194             return encodeArrayLoop(src, dst);
 195         else
 196             return encodeBufferLoop(src, dst);
 197     }
 198 
 199 }