1 /* 2 * Copyright (c) 2008, 2019, 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 { withResult(CoderResult cr, Buffer src, int sp, Buffer dst, int dp)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 private final boolean isASCIICompatible; 53 private final boolean isLatin1Decodable; 54 Decoder(Charset cs, char[] b2c)55 public Decoder(Charset cs, char[] b2c) { 56 super(cs, 1.0f, 1.0f); 57 this.b2c = b2c; 58 this.isASCIICompatible = false; 59 this.isLatin1Decodable = false; 60 } 61 Decoder(Charset cs, char[] b2c, boolean isASCIICompatible)62 public Decoder(Charset cs, char[] b2c, boolean isASCIICompatible) { 63 super(cs, 1.0f, 1.0f); 64 this.b2c = b2c; 65 this.isASCIICompatible = isASCIICompatible; 66 this.isLatin1Decodable = false; 67 } 68 Decoder(Charset cs, char[] b2c, boolean isASCIICompatible, boolean isLatin1Decodable)69 public Decoder(Charset cs, char[] b2c, boolean isASCIICompatible, boolean isLatin1Decodable) { 70 super(cs, 1.0f, 1.0f); 71 this.b2c = b2c; 72 this.isASCIICompatible = isASCIICompatible; 73 this.isLatin1Decodable = isLatin1Decodable; 74 } 75 decodeArrayLoop(ByteBuffer src, CharBuffer dst)76 private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) { 77 byte[] sa = src.array(); 78 int sp = src.arrayOffset() + src.position(); 79 int sl = src.arrayOffset() + src.limit(); 80 81 char[] da = dst.array(); 82 int dp = dst.arrayOffset() + dst.position(); 83 int dl = dst.arrayOffset() + dst.limit(); 84 85 CoderResult cr = CoderResult.UNDERFLOW; 86 if ((dl - dp) < (sl - sp)) { 87 sl = sp + (dl - dp); 88 cr = CoderResult.OVERFLOW; 89 } 90 91 while (sp < sl) { 92 char c = decode(sa[sp]); 93 if (c == UNMAPPABLE_DECODING) { 94 return withResult(CoderResult.unmappableForLength(1), 95 src, sp, dst, dp); 96 } 97 da[dp++] = c; 98 sp++; 99 } 100 return withResult(cr, src, sp, dst, dp); 101 } 102 decodeBufferLoop(ByteBuffer src, CharBuffer dst)103 private CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) { 104 int mark = src.position(); 105 try { 106 while (src.hasRemaining()) { 107 char c = decode(src.get()); 108 if (c == UNMAPPABLE_DECODING) 109 return CoderResult.unmappableForLength(1); 110 if (!dst.hasRemaining()) 111 return CoderResult.OVERFLOW; 112 dst.put(c); 113 mark++; 114 } 115 return CoderResult.UNDERFLOW; 116 } finally { 117 src.position(mark); 118 } 119 } 120 decodeLoop(ByteBuffer src, CharBuffer dst)121 protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) { 122 if (src.hasArray() && dst.hasArray()) 123 return decodeArrayLoop(src, dst); 124 else 125 return decodeBufferLoop(src, dst); 126 } 127 decode(int b)128 public final char decode(int b) { 129 return b2c[b + 128]; 130 } 131 132 private char repl = '\uFFFD'; implReplaceWith(String newReplacement)133 protected void implReplaceWith(String newReplacement) { 134 repl = newReplacement.charAt(0); 135 } 136 137 @Override decodeToLatin1(byte[] src, int sp, int len, byte[] dst)138 public int decodeToLatin1(byte[] src, int sp, int len, byte[] dst) { 139 if (len > dst.length) 140 len = dst.length; 141 142 int dp = 0; 143 while (dp < len) { 144 dst[dp++] = (byte)decode(src[sp++]); 145 } 146 return dp; 147 } 148 149 @Override decode(byte[] src, int sp, int len, char[] dst)150 public int decode(byte[] src, int sp, int len, char[] dst) { 151 if (len > dst.length) 152 len = dst.length; 153 int dp = 0; 154 while (dp < len) { 155 dst[dp] = decode(src[sp++]); 156 if (dst[dp] == UNMAPPABLE_DECODING) { 157 dst[dp] = repl; 158 } 159 dp++; 160 } 161 return dp; 162 } 163 164 @Override isASCIICompatible()165 public boolean isASCIICompatible() { 166 return isASCIICompatible; 167 } 168 169 @Override isLatin1Decodable()170 public boolean isLatin1Decodable() { 171 return isLatin1Decodable; 172 } 173 } 174 175 public static final class Encoder extends CharsetEncoder 176 implements ArrayEncoder { 177 private Surrogate.Parser sgp; 178 private final char[] c2b; 179 private final char[] c2bIndex; 180 private final boolean isASCIICompatible; 181 Encoder(Charset cs, char[] c2b, char[] c2bIndex, boolean isASCIICompatible)182 public Encoder(Charset cs, char[] c2b, char[] c2bIndex, boolean isASCIICompatible) { 183 super(cs, 1.0f, 1.0f); 184 this.c2b = c2b; 185 this.c2bIndex = c2bIndex; 186 this.isASCIICompatible = isASCIICompatible; 187 } 188 canEncode(char c)189 public boolean canEncode(char c) { 190 return encode(c) != UNMAPPABLE_ENCODING; 191 } 192 isLegalReplacement(byte[] repl)193 public boolean isLegalReplacement(byte[] repl) { 194 return ((repl.length == 1 && repl[0] == (byte)'?') || 195 super.isLegalReplacement(repl)); 196 } 197 encodeArrayLoop(CharBuffer src, ByteBuffer dst)198 private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { 199 char[] sa = src.array(); 200 int sp = src.arrayOffset() + src.position(); 201 int sl = src.arrayOffset() + src.limit(); 202 203 byte[] da = dst.array(); 204 int dp = dst.arrayOffset() + dst.position(); 205 int dl = dst.arrayOffset() + dst.limit(); 206 int len = Math.min(dl - dp, sl - sp); 207 208 while (len-- > 0) { 209 char c = sa[sp]; 210 int b = encode(c); 211 if (b == UNMAPPABLE_ENCODING) { 212 if (Character.isSurrogate(c)) { 213 if (sgp == null) 214 sgp = new Surrogate.Parser(); 215 if (sgp.parse(c, sa, sp, sl) < 0) { 216 return withResult(sgp.error(), src, sp, dst, dp); 217 } 218 return withResult(sgp.unmappableResult(), src, sp, dst, dp); 219 } 220 return withResult(CoderResult.unmappableForLength(1), 221 src, sp, dst, dp); 222 } 223 da[dp++] = (byte)b; 224 sp++; 225 } 226 return withResult(sp < sl ? CoderResult.OVERFLOW : CoderResult.UNDERFLOW, 227 src, sp, dst, dp); 228 } 229 encodeBufferLoop(CharBuffer src, ByteBuffer dst)230 private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) { 231 int mark = src.position(); 232 try { 233 while (src.hasRemaining()) { 234 char c = src.get(); 235 int b = encode(c); 236 if (b == UNMAPPABLE_ENCODING) { 237 if (Character.isSurrogate(c)) { 238 if (sgp == null) 239 sgp = new Surrogate.Parser(); 240 if (sgp.parse(c, src) < 0) 241 return sgp.error(); 242 return sgp.unmappableResult(); 243 } 244 return CoderResult.unmappableForLength(1); 245 } 246 if (!dst.hasRemaining()) 247 return CoderResult.OVERFLOW; 248 dst.put((byte)b); 249 mark++; 250 } 251 return CoderResult.UNDERFLOW; 252 } finally { 253 src.position(mark); 254 } 255 } 256 encodeLoop(CharBuffer src, ByteBuffer dst)257 protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) { 258 if (src.hasArray() && dst.hasArray()) 259 return encodeArrayLoop(src, dst); 260 else 261 return encodeBufferLoop(src, dst); 262 } 263 encode(char ch)264 public final int encode(char ch) { 265 char index = c2bIndex[ch >> 8]; 266 if (index == UNMAPPABLE_ENCODING) 267 return UNMAPPABLE_ENCODING; 268 return c2b[index + (ch & 0xff)]; 269 } 270 271 private byte repl = (byte)'?'; implReplaceWith(byte[] newReplacement)272 protected void implReplaceWith(byte[] newReplacement) { 273 repl = newReplacement[0]; 274 } 275 encode(char[] src, int sp, int len, byte[] dst)276 public int encode(char[] src, int sp, int len, byte[] dst) { 277 int dp = 0; 278 int sl = sp + Math.min(len, dst.length); 279 while (sp < sl) { 280 char c = src[sp++]; 281 int b = encode(c); 282 if (b != UNMAPPABLE_ENCODING) { 283 dst[dp++] = (byte)b; 284 continue; 285 } 286 if (Character.isHighSurrogate(c) && sp < sl && 287 Character.isLowSurrogate(src[sp])) { 288 if (len > dst.length) { 289 sl++; 290 len--; 291 } 292 sp++; 293 } 294 dst[dp++] = repl; 295 } 296 return dp; 297 } 298 299 @Override encodeFromLatin1(byte[] src, int sp, int len, byte[] dst)300 public int encodeFromLatin1(byte[] src, int sp, int len, byte[] dst) { 301 int dp = 0; 302 int sl = sp + Math.min(len, dst.length); 303 while (sp < sl) { 304 char c = (char)(src[sp++] & 0xff); 305 int b = encode(c); 306 if (b == UNMAPPABLE_ENCODING) { 307 dst[dp++] = repl; 308 } else { 309 dst[dp++] = (byte)b; 310 } 311 } 312 return dp; 313 } 314 315 @Override encodeFromUTF16(byte[] src, int sp, int len, byte[] dst)316 public int encodeFromUTF16(byte[] src, int sp, int len, byte[] dst) { 317 int dp = 0; 318 int sl = sp + Math.min(len, dst.length); 319 while (sp < sl) { 320 char c = StringUTF16.getChar(src, sp++); 321 int b = encode(c); 322 if (b != UNMAPPABLE_ENCODING) { 323 dst[dp++] = (byte)b; 324 continue; 325 } 326 if (Character.isHighSurrogate(c) && sp < sl && 327 Character.isLowSurrogate(StringUTF16.getChar(src, sp))) { 328 if (len > dst.length) { 329 sl++; 330 len--; 331 } 332 sp++; 333 } 334 dst[dp++] = repl; 335 } 336 return dp; 337 } 338 339 @Override isASCIICompatible()340 public boolean isASCIICompatible() { 341 return isASCIICompatible; 342 } 343 } 344 345 // init the c2b and c2bIndex tables from b2c. initC2B(char[] b2c, char[] c2bNR, char[] c2b, char[] c2bIndex)346 public static void initC2B(char[] b2c, char[] c2bNR, 347 char[] c2b, char[] c2bIndex) { 348 for (int i = 0; i < c2bIndex.length; i++) 349 c2bIndex[i] = UNMAPPABLE_ENCODING; 350 for (int i = 0; i < c2b.length; i++) 351 c2b[i] = UNMAPPABLE_ENCODING; 352 int off = 0; 353 for (int i = 0; i < b2c.length; i++) { 354 char c = b2c[i]; 355 if (c == UNMAPPABLE_DECODING) 356 continue; 357 int index = (c >> 8); 358 if (c2bIndex[index] == UNMAPPABLE_ENCODING) { 359 c2bIndex[index] = (char)off; 360 off += 0x100; 361 } 362 index = c2bIndex[index] + (c & 0xff); 363 c2b[index] = (char)((i>=0x80)?(i-0x80):(i+0x80)); 364 } 365 if (c2bNR != null) { 366 // c-->b nr entries 367 int i = 0; 368 while (i < c2bNR.length) { 369 char b = c2bNR[i++]; 370 char c = c2bNR[i++]; 371 int index = (c >> 8); 372 if (c2bIndex[index] == UNMAPPABLE_ENCODING) { 373 c2bIndex[index] = (char)off; 374 off += 0x100; 375 } 376 index = c2bIndex[index] + (c & 0xff); 377 c2b[index] = b; 378 } 379 } 380 } 381 } 382