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