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