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