1 /*
   2  * Copyright (c) 2003, 2018, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /*
  27  */
  28 
  29 package $PACKAGE$;
  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 public abstract class SimpleEUCEncoder
  40     extends CharsetEncoder
  41 {
  42 
  43     protected short  index1[];
  44     protected String index2;
  45     protected String index2a;
  46     protected String index2b;
  47     protected String index2c;
  48     protected int    mask1;
  49     protected int    mask2;
  50     protected int    shift;
  51 
  52     private byte[] outputByte = new byte[4];
  53     private final Surrogate.Parser sgp = new Surrogate.Parser();
  54 
  55     protected SimpleEUCEncoder(Charset cs)
  56     {
  57         super(cs, 3.0f, 4.0f);
  58     }
  59 
  60     /**
  61      * Returns true if the given character can be converted to the
  62      * target character encoding.
  63      */
  64 
  65     public boolean canEncode(char ch) {
  66        int    index;
  67        String theChars;
  68 
  69        index = index1[((ch & mask1) >> shift)] + (ch & mask2);
  70 
  71        if (index < 7500)
  72          theChars = index2;
  73        else
  74          if (index < 15000) {
  75            index = index - 7500;
  76            theChars = index2a;
  77          }
  78          else
  79            if (index < 22500){
  80              index = index - 15000;
  81              theChars = index2b;
  82            }
  83            else {
  84              index = index - 22500;
  85              theChars = index2c;
  86            }
  87 
  88        if (theChars.charAt(2*index) != '\u0000' ||
  89                     theChars.charAt(2*index + 1) != '\u0000')
  90          return (true);
  91 
  92        // only return true if input char was unicode null - all others are
  93        //     undefined
  94        return( ch == '\u0000');
  95 
  96     }
  97     private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
  98         char[] sa = src.array();
  99         int sp = src.arrayOffset() + src.position();
 100         int sl = src.arrayOffset() + src.limit();
 101         assert (sp <= sl);
 102         sp = (sp <= sl ? sp : sl);
 103         byte[] da = dst.array();
 104         int dp = dst.arrayOffset() + dst.position();
 105         int dl = dst.arrayOffset() + dst.limit();
 106         assert (dp <= dl);
 107         dp = (dp <= dl ? dp : dl);
 108 
 109         int     index;
 110         int     spaceNeeded;
 111         int     i;
 112 
 113         try {
 114             while (sp < sl) {
 115                 boolean allZeroes = true;
 116                 char inputChar = sa[sp];
 117                 if (Character.isSurrogate(inputChar)) {
 118                     if (sgp.parse(inputChar, sa, sp, sl) < 0)
 119                         return sgp.error();
 120                     return sgp.unmappableResult();
 121                 }
 122 
 123                 if (inputChar >= '\uFFFE')
 124                     return CoderResult.unmappableForLength(1);
 125 
 126                 String theChars;
 127                 char   aChar;
 128 
 129                  // We have a valid character, get the bytes for it
 130                 index = index1[((inputChar & mask1) >> shift)] + (inputChar & mask2);
 131 
 132                 if (index < 7500)
 133                     theChars = index2;
 134                 else if (index < 15000) {
 135                      index = index - 7500;
 136                      theChars = index2a;
 137                 } else if (index < 22500){
 138                     index = index - 15000;
 139                     theChars = index2b;
 140                 }
 141                 else {
 142                     index = index - 22500;
 143                     theChars = index2c;
 144                 }
 145 
 146                 aChar = theChars.charAt(2*index);
 147                 outputByte[0] = (byte)((aChar & 0xff00)>>8);
 148                 outputByte[1] = (byte)(aChar & 0x00ff);
 149                 aChar = theChars.charAt(2*index + 1);
 150                 outputByte[2] = (byte)((aChar & 0xff00)>>8);
 151                 outputByte[3] = (byte)(aChar & 0x00ff);
 152 
 153             for (i = 0; i < outputByte.length; i++) {
 154                 if (outputByte[i] != 0x00) {
 155                 allZeroes = false;
 156                 break;
 157                 }
 158             }
 159 
 160             if (allZeroes && inputChar != '\u0000') {
 161                 return CoderResult.unmappableForLength(1);
 162             }
 163 
 164             int oindex = 0;
 165 
 166             for (spaceNeeded = outputByte.length;
 167                  spaceNeeded > 1; spaceNeeded--){
 168                 if (outputByte[oindex++] != 0x00 )
 169                     break;
 170             }
 171 
 172             if (dp + spaceNeeded > dl)
 173                 return CoderResult.OVERFLOW;
 174 
 175             for (i = outputByte.length - spaceNeeded;
 176                  i < outputByte.length; i++) {
 177                     da[dp++] = outputByte[i];
 178             }
 179             sp++;
 180         }
 181         return CoderResult.UNDERFLOW;
 182         } finally {
 183             src.position(sp - src.arrayOffset());
 184             dst.position(dp - dst.arrayOffset());
 185         }
 186     }
 187 
 188     private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
 189         int     index;
 190         int     spaceNeeded;
 191         int     i;
 192         int mark = src.position();
 193         try {
 194             while (src.hasRemaining()) {
 195                 char inputChar = src.get();
 196                 boolean allZeroes = true;
 197                 if (Character.isSurrogate(inputChar)) {
 198                     if (sgp.parse(inputChar, src) < 0)
 199                         return sgp.error();
 200                     return sgp.unmappableResult();
 201                 }
 202 
 203                 if (inputChar >= '\uFFFE')
 204                     return CoderResult.unmappableForLength(1);
 205 
 206                 String theChars;
 207                 char   aChar;
 208 
 209                  // We have a valid character, get the bytes for it
 210                 index = index1[((inputChar & mask1) >> shift)] + (inputChar & mask2);
 211 
 212                 if (index < 7500)
 213                     theChars = index2;
 214                 else if (index < 15000) {
 215                      index = index - 7500;
 216                      theChars = index2a;
 217                 } else if (index < 22500){
 218                     index = index - 15000;
 219                     theChars = index2b;
 220                 }
 221                 else {
 222                     index = index - 22500;
 223                     theChars = index2c;
 224                 }
 225 
 226                 aChar = theChars.charAt(2*index);
 227                 outputByte[0] = (byte)((aChar & 0xff00)>>8);
 228                 outputByte[1] = (byte)(aChar & 0x00ff);
 229                 aChar = theChars.charAt(2*index + 1);
 230                 outputByte[2] = (byte)((aChar & 0xff00)>>8);
 231                 outputByte[3] = (byte)(aChar & 0x00ff);
 232 
 233             for (i = 0; i < outputByte.length; i++) {
 234                 if (outputByte[i] != 0x00) {
 235                 allZeroes = false;
 236                 break;
 237                 }
 238             }
 239             if (allZeroes && inputChar != '\u0000') {
 240                 return CoderResult.unmappableForLength(1);
 241             }
 242 
 243             int oindex = 0;
 244 
 245             for (spaceNeeded = outputByte.length;
 246                  spaceNeeded > 1; spaceNeeded--){
 247                 if (outputByte[oindex++] != 0x00 )
 248                     break;
 249             }
 250             if (dst.remaining() < spaceNeeded)
 251                 return CoderResult.OVERFLOW;
 252 
 253             for (i = outputByte.length - spaceNeeded;
 254                  i < outputByte.length; i++) {
 255                     dst.put(outputByte[i]);
 256             }
 257             mark++;
 258             }
 259             return CoderResult.UNDERFLOW;
 260         } finally {
 261             src.position(mark);
 262         }
 263     }
 264 
 265     protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
 266         if (true && src.hasArray() && dst.hasArray())
 267             return encodeArrayLoop(src, dst);
 268         else
 269             return encodeBufferLoop(src, dst);
 270     }
 271 
 272     public byte encode(char inputChar) {
 273         return (byte)index2.charAt(index1[(inputChar & mask1) >> shift] +
 274                 (inputChar & mask2));
 275     }
 276 }