SingleByte.java revision 12745:f068a4ffddd2
1/* 2 * Copyright (c) 2008, 2012, 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 26package sun.nio.cs; 27 28import java.nio.Buffer; 29import java.nio.ByteBuffer; 30import java.nio.CharBuffer; 31import java.nio.charset.Charset; 32import java.nio.charset.CharsetDecoder; 33import java.nio.charset.CharsetEncoder; 34import java.nio.charset.CoderResult; 35import java.util.Arrays; 36import static sun.nio.cs.CharsetMapping.*; 37 38public class SingleByte 39{ 40 private static final CoderResult withResult(CoderResult cr, 41 Buffer src, int sp, 42 Buffer dst, int dp) 43 { 44 src.position(sp - src.arrayOffset()); 45 dst.position(dp - dst.arrayOffset()); 46 return cr; 47 } 48 49 public static final class Decoder extends CharsetDecoder 50 implements ArrayDecoder { 51 private final char[] b2c; 52 53 public Decoder(Charset cs, char[] b2c) { 54 super(cs, 1.0f, 1.0f); 55 this.b2c = b2c; 56 } 57 58 private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) { 59 byte[] sa = src.array(); 60 int sp = src.arrayOffset() + src.position(); 61 int sl = src.arrayOffset() + src.limit(); 62 63 char[] da = dst.array(); 64 int dp = dst.arrayOffset() + dst.position(); 65 int dl = dst.arrayOffset() + dst.limit(); 66 67 CoderResult cr = CoderResult.UNDERFLOW; 68 if ((dl - dp) < (sl - sp)) { 69 sl = sp + (dl - dp); 70 cr = CoderResult.OVERFLOW; 71 } 72 73 while (sp < sl) { 74 char c = decode(sa[sp]); 75 if (c == UNMAPPABLE_DECODING) { 76 return withResult(CoderResult.unmappableForLength(1), 77 src, sp, dst, dp); 78 } 79 da[dp++] = c; 80 sp++; 81 } 82 return withResult(cr, src, sp, dst, dp); 83 } 84 85 private CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) { 86 int mark = src.position(); 87 try { 88 while (src.hasRemaining()) { 89 char c = decode(src.get()); 90 if (c == UNMAPPABLE_DECODING) 91 return CoderResult.unmappableForLength(1); 92 if (!dst.hasRemaining()) 93 return CoderResult.OVERFLOW; 94 dst.put(c); 95 mark++; 96 } 97 return CoderResult.UNDERFLOW; 98 } finally { 99 src.position(mark); 100 } 101 } 102 103 protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) { 104 if (src.hasArray() && dst.hasArray()) 105 return decodeArrayLoop(src, dst); 106 else 107 return decodeBufferLoop(src, dst); 108 } 109 110 public final char decode(int b) { 111 return b2c[b + 128]; 112 } 113 114 private char repl = '\uFFFD'; 115 protected void implReplaceWith(String newReplacement) { 116 repl = newReplacement.charAt(0); 117 } 118 119 public int decode(byte[] src, int sp, int len, char[] dst) { 120 if (len > dst.length) 121 len = dst.length; 122 int dp = 0; 123 while (dp < len) { 124 dst[dp] = decode(src[sp++]); 125 if (dst[dp] == UNMAPPABLE_DECODING) { 126 dst[dp] = repl; 127 } 128 dp++; 129 } 130 return dp; 131 } 132 } 133 134 public static final class Encoder extends CharsetEncoder 135 implements ArrayEncoder { 136 private Surrogate.Parser sgp; 137 private final char[] c2b; 138 private final char[] c2bIndex; 139 140 public Encoder(Charset cs, char[] c2b, char[] c2bIndex) { 141 super(cs, 1.0f, 1.0f); 142 this.c2b = c2b; 143 this.c2bIndex = c2bIndex; 144 } 145 146 public boolean canEncode(char c) { 147 return encode(c) != UNMAPPABLE_ENCODING; 148 } 149 150 public boolean isLegalReplacement(byte[] repl) { 151 return ((repl.length == 1 && repl[0] == (byte)'?') || 152 super.isLegalReplacement(repl)); 153 } 154 155 private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { 156 char[] sa = src.array(); 157 int sp = src.arrayOffset() + src.position(); 158 int sl = src.arrayOffset() + src.limit(); 159 160 byte[] da = dst.array(); 161 int dp = dst.arrayOffset() + dst.position(); 162 int dl = dst.arrayOffset() + dst.limit(); 163 int len = Math.min(dl - dp, sl - sp); 164 165 while (len-- > 0) { 166 char c = sa[sp]; 167 int b = encode(c); 168 if (b == UNMAPPABLE_ENCODING) { 169 if (Character.isSurrogate(c)) { 170 if (sgp == null) 171 sgp = new Surrogate.Parser(); 172 if (sgp.parse(c, sa, sp, sl) < 0) { 173 return withResult(sgp.error(), src, sp, dst, dp); 174 } 175 return withResult(sgp.unmappableResult(), src, sp, dst, dp); 176 } 177 return withResult(CoderResult.unmappableForLength(1), 178 src, sp, dst, dp); 179 } 180 da[dp++] = (byte)b; 181 sp++; 182 } 183 return withResult(sp < sl ? CoderResult.OVERFLOW : CoderResult.UNDERFLOW, 184 src, sp, dst, dp); 185 } 186 187 private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) { 188 int mark = src.position(); 189 try { 190 while (src.hasRemaining()) { 191 char c = src.get(); 192 int b = encode(c); 193 if (b == UNMAPPABLE_ENCODING) { 194 if (Character.isSurrogate(c)) { 195 if (sgp == null) 196 sgp = new Surrogate.Parser(); 197 if (sgp.parse(c, src) < 0) 198 return sgp.error(); 199 return sgp.unmappableResult(); 200 } 201 return CoderResult.unmappableForLength(1); 202 } 203 if (!dst.hasRemaining()) 204 return CoderResult.OVERFLOW; 205 dst.put((byte)b); 206 mark++; 207 } 208 return CoderResult.UNDERFLOW; 209 } finally { 210 src.position(mark); 211 } 212 } 213 214 protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) { 215 if (src.hasArray() && dst.hasArray()) 216 return encodeArrayLoop(src, dst); 217 else 218 return encodeBufferLoop(src, dst); 219 } 220 221 public final int encode(char ch) { 222 char index = c2bIndex[ch >> 8]; 223 if (index == UNMAPPABLE_ENCODING) 224 return UNMAPPABLE_ENCODING; 225 return c2b[index + (ch & 0xff)]; 226 } 227 228 private byte repl = (byte)'?'; 229 protected void implReplaceWith(byte[] newReplacement) { 230 repl = newReplacement[0]; 231 } 232 233 public int encode(char[] src, int sp, int len, byte[] dst) { 234 int dp = 0; 235 int sl = sp + Math.min(len, dst.length); 236 while (sp < sl) { 237 char c = src[sp++]; 238 int b = encode(c); 239 if (b != UNMAPPABLE_ENCODING) { 240 dst[dp++] = (byte)b; 241 continue; 242 } 243 if (Character.isHighSurrogate(c) && sp < sl && 244 Character.isLowSurrogate(src[sp])) { 245 if (len > dst.length) { 246 sl++; 247 len--; 248 } 249 sp++; 250 } 251 dst[dp++] = repl; 252 } 253 return dp; 254 } 255 } 256 257 // init the c2b and c2bIndex tables from b2c. 258 public static void initC2B(char[] b2c, char[] c2bNR, 259 char[] c2b, char[] c2bIndex) { 260 for (int i = 0; i < c2bIndex.length; i++) 261 c2bIndex[i] = UNMAPPABLE_ENCODING; 262 for (int i = 0; i < c2b.length; i++) 263 c2b[i] = UNMAPPABLE_ENCODING; 264 int off = 0; 265 for (int i = 0; i < b2c.length; i++) { 266 char c = b2c[i]; 267 if (c == UNMAPPABLE_DECODING) 268 continue; 269 int index = (c >> 8); 270 if (c2bIndex[index] == UNMAPPABLE_ENCODING) { 271 c2bIndex[index] = (char)off; 272 off += 0x100; 273 } 274 index = c2bIndex[index] + (c & 0xff); 275 c2b[index] = (char)((i>=0x80)?(i-0x80):(i+0x80)); 276 } 277 if (c2bNR != null) { 278 // c-->b nr entries 279 int i = 0; 280 while (i < c2bNR.length) { 281 char b = c2bNR[i++]; 282 char c = c2bNR[i++]; 283 int index = (c >> 8); 284 if (c2bIndex[index] == UNMAPPABLE_ENCODING) { 285 c2bIndex[index] = (char)off; 286 off += 0x100; 287 } 288 index = c2bIndex[index] + (c & 0xff); 289 c2b[index] = b; 290 } 291 } 292 } 293} 294