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