1 /* 2 * Copyright (c) 2008, 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 package sun.nio.cs; 27 28 import java.nio.Buffer; 29 import java.nio.ByteBuffer; 30 import java.nio.CharBuffer; 31 import java.nio.charset.Charset; 32 import java.nio.charset.CharsetDecoder; 33 import java.nio.charset.CharsetEncoder; 34 import java.nio.charset.CoderResult; 35 import java.util.Arrays; 36 import static sun.nio.cs.CharsetMapping.*; 37 38 public 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 final public static 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 final public static 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 164 CoderResult cr = CoderResult.UNDERFLOW; 165 if ((dl - dp) < (sl - sp)) { 166 sl = sp + (dl - dp); 167 cr = CoderResult.OVERFLOW; 168 } 169 170 while (sp < sl) { 171 char c = sa[sp]; 172 int b = encode(c); 173 if (b == UNMAPPABLE_ENCODING) { 174 if (Character.isSurrogate(c)) { 175 if (sgp == null) 176 sgp = new Surrogate.Parser(); 177 if (sgp.parse(c, sa, sp, sl) < 0) 178 return withResult(sgp.error(), src, sp, dst, dp); 179 return withResult(sgp.unmappableResult(), src, sp, dst, dp); 180 } 181 return withResult(CoderResult.unmappableForLength(1), 182 src, sp, dst, dp); 183 } 184 da[dp++] = (byte)b; 185 sp++; 186 } 187 return withResult(cr, src, sp, dst, dp); 188 } 189 190 private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) { 191 int mark = src.position(); 192 try { 193 while (src.hasRemaining()) { 194 char c = src.get(); 195 int b = encode(c); 196 if (b == UNMAPPABLE_ENCODING) { 197 if (Character.isSurrogate(c)) { 198 if (sgp == null) 199 sgp = new Surrogate.Parser(); 200 if (sgp.parse(c, src) < 0) 201 return sgp.error(); 202 return sgp.unmappableResult(); 203 } 204 return CoderResult.unmappableForLength(1); 205 } 206 if (!dst.hasRemaining()) 207 return CoderResult.OVERFLOW; 208 dst.put((byte)b); 209 mark++; 210 } 211 return CoderResult.UNDERFLOW; 212 } finally { 213 src.position(mark); 214 } 215 } 216 217 protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) { 218 if (src.hasArray() && dst.hasArray()) 219 return encodeArrayLoop(src, dst); 220 else 221 return encodeBufferLoop(src, dst); 222 } 223 224 public final int encode(char ch) { 225 char index = c2bIndex[ch >> 8]; 226 if (index == UNMAPPABLE_ENCODING) 227 return UNMAPPABLE_ENCODING; 228 return c2b[index + (ch & 0xff)]; 229 } 230 231 private byte repl = (byte)'?'; 232 protected void implReplaceWith(byte[] newReplacement) { 233 repl = newReplacement[0]; 234 } 235 236 public int encode(char[] src, int sp, int len, byte[] dst) { 237 int dp = 0; 238 int sl = sp + Math.min(len, dst.length); 239 while (sp < sl) { 240 char c = src[sp++]; 241 int b = encode(c); 242 if (b != UNMAPPABLE_ENCODING) { 243 dst[dp++] = (byte)b; 244 continue; 245 } 246 if (Character.isHighSurrogate(c) && sp < sl && 247 Character.isLowSurrogate(src[sp])) { 248 if (len > dst.length) { 249 sl++; 250 len--; 251 } 252 sp++; 253 } 254 dst[dp++] = repl; 255 } 256 return dp; 257 } 258 } 259 260 // init the c2b and c2bIndex tables from b2c. 261 public static void initC2B(char[] b2c, char[] c2bNR, 262 char[] c2b, char[] c2bIndex) { 263 for (int i = 0; i < c2bIndex.length; i++) 264 c2bIndex[i] = UNMAPPABLE_ENCODING; 265 for (int i = 0; i < c2b.length; i++) 266 c2b[i] = UNMAPPABLE_ENCODING; 267 int off = 0; 268 for (int i = 0; i < b2c.length; i++) { 269 char c = b2c[i]; 270 if (c == UNMAPPABLE_DECODING) 271 continue; 272 int index = (c >> 8); 273 if (c2bIndex[index] == UNMAPPABLE_ENCODING) { 274 c2bIndex[index] = (char)off; 275 off += 0x100; 276 } 277 index = c2bIndex[index] + (c & 0xff); 278 c2b[index] = (char)((i>=0x80)?(i-0x80):(i+0x80)); 279 } 280 if (c2bNR != null) { 281 // c-->b nr entries 282 int i = 0; 283 while (i < c2bNR.length) { 284 char b = c2bNR[i++]; 285 char c = c2bNR[i++]; 286 int index = (c >> 8); 287 if (c2bIndex[index] == UNMAPPABLE_ENCODING) { 288 c2bIndex[index] = (char)off; 289 off += 0x100; 290 } 291 index = c2bIndex[index] + (c & 0xff); 292 c2b[index] = b; 293 } 294 } 295 } 296 }