1 /*
   2  * Copyright (c) 2002, 2006, 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 
  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 public abstract class DoubleByteEncoder
  38     extends CharsetEncoder
  39 {
  40 
  41     private short index1[];
  42     private String index2[];
  43 
  44     private final Surrogate.Parser sgp = new Surrogate.Parser();
  45 
  46     protected DoubleByteEncoder(Charset cs,
  47                                 short[] index1, String[] index2)
  48     {
  49         super(cs, 2.0f, 2.0f);
  50         this.index1 = index1;
  51         this.index2 = index2;
  52     }
  53 
  54     protected DoubleByteEncoder(Charset cs,
  55                                 short[] index1, String[] index2,
  56                                 float avg, float max)
  57     {
  58         super(cs, avg, max);
  59         this.index1 = index1;
  60         this.index2 = index2;
  61     }
  62 
  63     protected DoubleByteEncoder(Charset cs,
  64                                 short[] index1, String[] index2, byte[] repl)
  65     {
  66         super(cs, 2.0f, 2.0f, repl);
  67         this.index1 = index1;
  68         this.index2 = index2;
  69     }
  70 
  71 
  72     protected DoubleByteEncoder(Charset cs,
  73                                 short[] index1, String[] index2,
  74                                 byte[] repl, float avg, float max)
  75     {
  76         super(cs, avg, max,repl);
  77         this.index1 = index1;
  78         this.index2 = index2;
  79     }
  80 
  81     public boolean canEncode(char c) {
  82         return (encodeSingle(c) != -1 ||
  83                 encodeDouble(c) != 0);
  84     }
  85 
  86     private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {
  87         char[] sa = src.array();
  88         int sp = src.arrayOffset() + src.position();
  89         int sl = src.arrayOffset() + src.limit();
  90         byte[] da = dst.array();
  91         int dp = dst.arrayOffset() + dst.position();
  92         int dl = dst.arrayOffset() + dst.limit();
  93 
  94         try {
  95             while (sp < sl) {
  96                 char c = sa[sp];
  97                 if (Character.isSurrogate(c)) {
  98                     if (sgp.parse(c, sa, sp, sl) < 0)
  99                         return sgp.error();
 100                     if (sl - sp < 2)
 101                         return CoderResult.UNDERFLOW;
 102                     char c2 = sa[sp + 1];
 103 
 104                     byte[] outputBytes = new byte[2];
 105                     outputBytes = encodeSurrogate(c, c2);
 106 
 107                     if (outputBytes == null) {
 108                         return sgp.unmappableResult();
 109                     }
 110                     else {
 111                         if (dl - dp < 2)
 112                             return CoderResult.OVERFLOW;
 113                         da[dp++] = outputBytes[0];
 114                         da[dp++] = outputBytes[1];
 115                         sp += 2;
 116                         continue;
 117                     }
 118                 }
 119                 if (c >= '\uFFFE')
 120                     return CoderResult.unmappableForLength(1);
 121 
 122                 int b = encodeSingle(c);
 123                 if (b != -1) { // Single Byte
 124                     if (dl - dp < 1)
 125                         return CoderResult.OVERFLOW;
 126                     da[dp++] = (byte)b;
 127                     sp++;
 128                     continue;
 129                 }
 130 
 131                 int ncode  = encodeDouble(c);
 132                 if (ncode != 0 && c != '\u0000' ) {
 133                     if (dl - dp < 2)
 134                         return CoderResult.OVERFLOW;
 135                     da[dp++] = (byte) ((ncode & 0xff00) >> 8);
 136                     da[dp++] = (byte) (ncode & 0xff);
 137                     sp++;
 138                     continue;
 139                 }
 140                 return CoderResult.unmappableForLength(1);
 141                 }
 142             return CoderResult.UNDERFLOW;
 143         } finally {
 144             src.position(sp - src.arrayOffset());
 145             dst.position(dp - dst.arrayOffset());
 146         }
 147     }
 148 
 149     private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {
 150         int mark = src.position();
 151 
 152         try {
 153             while (src.hasRemaining()) {
 154                 char c = src.get();
 155                 if (Character.isSurrogate(c)) {
 156                     int surr;
 157                     if ((surr = sgp.parse(c, src)) < 0)
 158                         return sgp.error();
 159                     char c2 = Surrogate.low(surr);
 160                     byte[] outputBytes = new byte[2];
 161                     outputBytes = encodeSurrogate(c, c2);
 162 
 163                     if (outputBytes == null) {
 164                         return sgp.unmappableResult();
 165                     } else {
 166                         if (dst.remaining() < 2)
 167                             return CoderResult.OVERFLOW;
 168                         mark += 2;
 169                         dst.put(outputBytes[0]);
 170                         dst.put(outputBytes[1]);
 171                         continue;
 172                     }
 173                 }
 174                 if (c >= '\uFFFE')
 175                     return CoderResult.unmappableForLength(1);
 176                 int b = encodeSingle(c);
 177 
 178                 if (b != -1) { // Single-byte character
 179                     if (dst.remaining() < 1)
 180                         return CoderResult.OVERFLOW;
 181                     mark++;
 182                     dst.put((byte)b);
 183                     continue;
 184                 }
 185                 // Double Byte character
 186 
 187                 int ncode = encodeDouble(c);
 188                 if (ncode != 0 && c != '\u0000') {
 189                     if (dst.remaining() < 2)
 190                         return CoderResult.OVERFLOW;
 191                     mark++;
 192                     dst.put((byte) ((ncode & 0xff00) >> 8));
 193                     dst.put((byte) ncode);
 194                     continue;
 195                 }
 196                 return CoderResult.unmappableForLength(1);
 197             }
 198 
 199             return CoderResult.UNDERFLOW;
 200         } finally {
 201             src.position(mark);
 202         }
 203     }
 204 
 205     protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
 206         if (true && src.hasArray() && dst.hasArray())
 207             return encodeArrayLoop(src, dst);
 208         else
 209             return encodeBufferLoop(src, dst);
 210     }
 211 
 212     /*
 213      * Can be changed by subclass
 214      */
 215     protected int encodeDouble(char ch) {
 216         int offset = index1[((ch & 0xff00) >> 8 )] << 8;
 217         return index2[offset >> 12].charAt((offset & 0xfff) + (ch & 0xff));
 218     }
 219 
 220     /*
 221      * Can be changed by subclass
 222      */
 223     protected int encodeSingle(char inputChar) {
 224         if (inputChar < 0x80)
 225             return (byte)inputChar;
 226         else
 227             return -1;
 228     }
 229 
 230     /**
 231      *  Protected method which should be overridden by concrete DBCS
 232      *  CharsetEncoder classes which included supplementary characters
 233      *  within their mapping coverage.
 234      *  null return value indicates surrogate values could not be
 235      *  handled or encoded.
 236      */
 237     protected byte[] encodeSurrogate(char highSurrogate, char lowSurrogate) {
 238         return null;
 239     }
 240 }