1 /* 2 * Copyright (c) 2000, 2013, 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.ByteBuffer; 29 import java.nio.CharBuffer; 30 import java.nio.charset.Charset; 31 import java.nio.charset.CharsetDecoder; 32 import java.nio.charset.CharsetEncoder; 33 import java.nio.charset.CoderResult; 34 import java.util.Arrays; 35 import java.util.Objects; 36 37 import jdk.internal.HotSpotIntrinsicCandidate; 38 39 class ISO_8859_1 40 extends Charset 41 implements HistoricallyNamedCharset 42 { 43 44 public ISO_8859_1() { 45 super(StandardCharsets.ISO_8859_1, StandardCharsets.aliases_ISO_8859_1); 46 } 47 48 public String historicalName() { 49 return "ISO8859_1"; 50 } 51 52 public boolean contains(Charset cs) { 53 return ((cs instanceof US_ASCII) 54 || (cs instanceof ISO_8859_1)); 55 } 56 57 public CharsetDecoder newDecoder() { 58 return new Decoder(this); 59 } 60 61 public CharsetEncoder newEncoder() { 62 return new Encoder(this); 63 } 64 65 private static class Decoder extends CharsetDecoder 66 implements ArrayDecoder { 67 private Decoder(Charset cs) { 68 super(cs, 1.0f, 1.0f); 69 } 70 71 private CoderResult decodeArrayLoop(ByteBuffer src, 72 CharBuffer dst) 73 { 74 byte[] sa = src.array(); 75 int sp = src.arrayOffset() + src.position(); 76 int sl = src.arrayOffset() + src.limit(); 77 assert (sp <= sl); 78 sp = (sp <= sl ? sp : sl); 79 char[] da = dst.array(); 80 int dp = dst.arrayOffset() + dst.position(); 81 int dl = dst.arrayOffset() + dst.limit(); 82 assert (dp <= dl); 83 dp = (dp <= dl ? dp : dl); 84 85 try { 86 while (sp < sl) { 87 byte b = sa[sp]; 88 if (dp >= dl) 89 return CoderResult.OVERFLOW; 90 da[dp++] = (char)(b & 0xff); 91 sp++; 92 } 93 return CoderResult.UNDERFLOW; 94 } finally { 95 src.position(sp - src.arrayOffset()); 96 dst.position(dp - dst.arrayOffset()); 97 } 98 } 99 100 private CoderResult decodeBufferLoop(ByteBuffer src, 101 CharBuffer dst) 102 { 103 int mark = src.position(); 104 try { 105 while (src.hasRemaining()) { 106 byte b = src.get(); 107 if (!dst.hasRemaining()) 108 return CoderResult.OVERFLOW; 109 dst.put((char)(b & 0xff)); 110 mark++; 111 } 112 return CoderResult.UNDERFLOW; 113 } finally { 114 src.position(mark); 115 } 116 } 117 118 protected CoderResult decodeLoop(ByteBuffer src, 119 CharBuffer dst) 120 { 121 if (src.hasArray() && dst.hasArray()) 122 return decodeArrayLoop(src, dst); 123 else 124 return decodeBufferLoop(src, dst); 125 } 126 127 public int decode(byte[] src, int sp, int len, char[] dst) { 128 if (len > dst.length) 129 len = dst.length; 130 int dp = 0; 131 while (dp < len) 132 dst[dp++] = (char)(src[sp++] & 0xff); 133 return dp; 134 } 135 136 public boolean isASCIICompatible() { 137 return true; 138 } 139 } 140 141 private static class Encoder extends CharsetEncoder 142 implements ArrayEncoder { 143 private Encoder(Charset cs) { 144 super(cs, 1.0f, 1.0f); 145 } 146 147 public boolean canEncode(char c) { 148 return c <= '\u00FF'; 149 } 150 151 public boolean isLegalReplacement(byte[] repl) { 152 return true; // we accept any byte value 153 } 154 155 private final Surrogate.Parser sgp = new Surrogate.Parser(); 156 157 // Method possible replaced with a compiler intrinsic. 158 private static int encodeISOArray(char[] sa, int sp, 159 byte[] da, int dp, int len) { 160 if (len <= 0) { 161 return 0; 162 } 163 encodeISOArrayCheck(sa, sp, da, dp, len); 164 return implEncodeISOArray(sa, sp, da, dp, len); 165 } 166 167 @HotSpotIntrinsicCandidate 168 private static int implEncodeISOArray(char[] sa, int sp, 169 byte[] da, int dp, int len) 170 { 171 int i = 0; 172 for (; i < len; i++) { 173 char c = sa[sp++]; 174 if (c > '\u00FF') 175 break; 176 da[dp++] = (byte)c; 177 } 178 return i; 179 } 180 181 private static void encodeISOArrayCheck(char[] sa, int sp, 182 byte[] da, int dp, int len) { 183 Objects.requireNonNull(sa); 184 Objects.requireNonNull(da); 185 186 if (sp < 0 || sp >= sa.length) { 187 throw new ArrayIndexOutOfBoundsException(sp); 188 } 189 190 if (dp < 0 || dp >= da.length) { 191 throw new ArrayIndexOutOfBoundsException(dp); 192 } 193 194 int endIndexSP = sp + len - 1; 195 if (endIndexSP < 0 || endIndexSP >= sa.length) { 196 throw new ArrayIndexOutOfBoundsException(endIndexSP); 197 } 198 199 int endIndexDP = dp + len - 1; 200 if (endIndexDP < 0 || endIndexDP >= da.length) { 201 throw new ArrayIndexOutOfBoundsException(endIndexDP); 202 } 203 } 204 205 private CoderResult encodeArrayLoop(CharBuffer src, 206 ByteBuffer dst) 207 { 208 char[] sa = src.array(); 209 int soff = src.arrayOffset(); 210 int sp = soff + src.position(); 211 int sl = soff + src.limit(); 212 assert (sp <= sl); 213 sp = (sp <= sl ? sp : sl); 214 byte[] da = dst.array(); 215 int doff = dst.arrayOffset(); 216 int dp = doff + dst.position(); 217 int dl = doff + dst.limit(); 218 assert (dp <= dl); 219 dp = (dp <= dl ? dp : dl); 220 int dlen = dl - dp; 221 int slen = sl - sp; 222 int len = (dlen < slen) ? dlen : slen; 223 try { 224 int ret = encodeISOArray(sa, sp, da, dp, len); 225 sp = sp + ret; 226 dp = dp + ret; 227 if (ret != len) { 228 if (sgp.parse(sa[sp], sa, sp, sl) < 0) 229 return sgp.error(); 230 return sgp.unmappableResult(); 231 } 232 if (len < slen) 233 return CoderResult.OVERFLOW; 234 return CoderResult.UNDERFLOW; 235 } finally { 236 src.position(sp - soff); 237 dst.position(dp - doff); 238 } 239 } 240 241 private CoderResult encodeBufferLoop(CharBuffer src, 242 ByteBuffer dst) 243 { 244 int mark = src.position(); 245 try { 246 while (src.hasRemaining()) { 247 char c = src.get(); 248 if (c <= '\u00FF') { 249 if (!dst.hasRemaining()) 250 return CoderResult.OVERFLOW; 251 dst.put((byte)c); 252 mark++; 253 continue; 254 } 255 if (sgp.parse(c, src) < 0) 256 return sgp.error(); 257 return sgp.unmappableResult(); 258 } 259 return CoderResult.UNDERFLOW; 260 } finally { 261 src.position(mark); 262 } 263 } 264 265 protected CoderResult encodeLoop(CharBuffer src, 266 ByteBuffer dst) 267 { 268 if (src.hasArray() && dst.hasArray()) 269 return encodeArrayLoop(src, dst); 270 else 271 return encodeBufferLoop(src, dst); 272 } 273 274 private byte repl = (byte)'?'; 275 protected void implReplaceWith(byte[] newReplacement) { 276 repl = newReplacement[0]; 277 } 278 279 public int encode(char[] src, int sp, int len, byte[] dst) { 280 int dp = 0; 281 int slen = Math.min(len, dst.length); 282 int sl = sp + slen; 283 while (sp < sl) { 284 int ret = encodeISOArray(src, sp, dst, dp, slen); 285 sp = sp + ret; 286 dp = dp + ret; 287 if (ret != slen) { 288 char c = src[sp++]; 289 if (Character.isHighSurrogate(c) && sp < sl && 290 Character.isLowSurrogate(src[sp])) { 291 if (len > dst.length) { 292 sl++; 293 len--; 294 } 295 sp++; 296 } 297 dst[dp++] = repl; 298 slen = Math.min((sl - sp), (dst.length - dp)); 299 } 300 } 301 return dp; 302 } 303 304 public boolean isASCIICompatible() { 305 return true; 306 } 307 } 308 }