1 /*
   2  * Copyright (c) 2002, 2005, 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.CharsetDecoder;
  34 import java.nio.charset.CoderResult;
  35 
  36 abstract class DoubleByteDecoder
  37     extends CharsetDecoder
  38 {
  39 
  40     private short index1[];
  41 
  42     /*
  43      * 2nd level index, provided by subclass
  44      * every string has 0x10*(end-start+1) characters.
  45      */
  46     private String  index2[];
  47 
  48     protected int start;
  49     protected int end;
  50 
  51     protected static final char REPLACE_CHAR = '\uFFFD';
  52     protected char highSurrogate;
  53     protected char lowSurrogate;
  54 
  55     protected DoubleByteDecoder(Charset cs, short[] index1, String[] index2,
  56                                 int start, int end ) {
  57         super(cs, 0.5f, 1.0f);
  58         this.index1 = index1;
  59         this.index2 = index2;
  60         this.start = start;
  61         this.end = end;
  62     }
  63 
  64     private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {
  65         byte[] sa = src.array();
  66         int sp = src.arrayOffset() + src.position();
  67         int sl = src.arrayOffset() + src.limit();
  68         assert (sp <= sl);
  69         sp = (sp <= sl ? sp : sl);
  70         char[] da = dst.array();
  71         int dp = dst.arrayOffset() + dst.position();
  72         int dl = dst.arrayOffset() + dst.limit();
  73         assert (dp <= dl);
  74         dp = (dp <= dl ? dp : dl);
  75 
  76         try {
  77             while (sp < sl) {
  78                 int b1, b2;
  79                 b1 = sa[sp];
  80                 int inputSize = 1;
  81                 int outputSize = 1;
  82                 highSurrogate = lowSurrogate = 0;
  83                 char c = decodeSingle(b1);
  84                 if (c == REPLACE_CHAR) {
  85                     b1 &= 0xff;
  86                     if (sl - sp < 2)
  87                         return CoderResult.UNDERFLOW;
  88                     b2 = sa[sp + 1] & 0xff;
  89                     c = decodeDouble(b1, b2);
  90                     inputSize = 2;
  91                     if (c == REPLACE_CHAR)
  92                         return CoderResult.unmappableForLength(inputSize);
  93                     outputSize = (highSurrogate > 0) ? 2: 1;
  94                 }
  95 
  96                 if (dl - dp < outputSize)
  97                     return CoderResult.OVERFLOW;
  98                 if (outputSize == 2) {
  99                     da[dp++] = highSurrogate;
 100                     da[dp++] = lowSurrogate;
 101                 } else {
 102                     da[dp++] = c;
 103                 }
 104                 sp += inputSize;
 105             }
 106             return CoderResult.UNDERFLOW;
 107         } finally {
 108             src.position(sp - src.arrayOffset());
 109             dst.position(dp - dst.arrayOffset());
 110         }
 111     }
 112 
 113     private CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) {
 114         int mark = src.position();
 115         int inputSize = 0;
 116         int outputSize = 0;
 117         try {
 118             while (src.hasRemaining()) {
 119                 int b1 = src.get();
 120                 inputSize = 1;
 121                 outputSize = 1;
 122                 highSurrogate = lowSurrogate = 0;
 123 
 124                 char c = decodeSingle(b1);
 125 
 126                 if (c == REPLACE_CHAR) {
 127                     if (src.remaining() < 1)
 128                         return CoderResult.UNDERFLOW;
 129                     b1 &= 0xff;
 130                     int b2 = src.get() & 0xff;
 131                     inputSize = 2;
 132 
 133                     c = decodeDouble(b1, b2);
 134 
 135                     if (c == REPLACE_CHAR)
 136                         return CoderResult.unmappableForLength(2);
 137 
 138                     outputSize =  (highSurrogate > 0) ? 2: 1;
 139                 }
 140                 if (dst.remaining() < outputSize)
 141                     return CoderResult.OVERFLOW;
 142                 mark += inputSize;
 143 
 144                 if (outputSize == 2) {
 145                     dst.put(highSurrogate);
 146                     dst.put(lowSurrogate);
 147                 } else {
 148                     dst.put(c);
 149                 }
 150             }
 151             return CoderResult.UNDERFLOW;
 152         } finally {
 153             src.position(mark);
 154         }
 155     }
 156 
 157     protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
 158         if (src.hasArray() && dst.hasArray())
 159             return decodeArrayLoop(src, dst);
 160         else
 161             return decodeBufferLoop(src, dst);
 162     }
 163 
 164     /*
 165      * Can be changed by subclass
 166      */
 167     protected char decodeSingle(int b) {
 168         if (b >= 0)
 169             return (char) b;
 170         return REPLACE_CHAR;
 171     }
 172 
 173     protected char decodeDouble(int byte1, int byte2) {
 174         if (((byte1 < 0) || (byte1 > index1.length))
 175             || ((byte2 < start) || (byte2 > end)))
 176             return REPLACE_CHAR;
 177 
 178         int n = (index1[byte1] & 0xf) * (end - start + 1) + (byte2 - start);
 179         return index2[index1[byte1] >> 4].charAt(n);
 180     }
 181 }