1 /* 2 * Copyright (c) 1996, 2010, 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.io; 27 28 public class ByteToCharISO2022JP extends ByteToCharJIS0208 { 29 30 private static final int ASCII = 0; // ESC ( B 31 private static final int JISX0201_1976 = 1; // ESC ( J 32 private static final int JISX0208_1978 = 2; // ESC $ @ 33 private static final int JISX0208_1983 = 3; // ESC $ B 34 private static final int JISX0201_1976_KANA = 4; // ESC ( I 35 private static final int SHIFTOUT = 5; // SO (0x0e) 36 37 private int currentState; 38 private int savedSize; 39 private byte[] savedBytes; 40 41 public ByteToCharISO2022JP() { 42 super(); 43 savedBytes = new byte[2]; 44 currentState = ASCII; 45 savedSize = 0; 46 } 47 48 public int flush(char [] output, int outStart, int outEnd) 49 throws MalformedInputException 50 { 51 if (savedSize != 0) { 52 savedSize = 0; 53 currentState = ASCII; 54 badInputLength = 0; 55 throw new MalformedInputException(); 56 } 57 byteOff = charOff = 0; 58 return 0; 59 } 60 61 62 /** 63 * Character conversion 64 */ 65 public int convert(byte[] input, int inOff, int inEnd, 66 char[] output, int outOff, int outEnd) 67 throws UnknownCharacterException, MalformedInputException, 68 ConversionBufferFullException 69 { 70 int previousState = ASCII; 71 int inputSize = 0; 72 char outputChar = '\uFFFD'; 73 // readOff keeps the actual buffer's pointer. 74 // byteOff keeps original buffer's pointer. 75 int readOff = byteOff = inOff; 76 77 if (savedSize != 0) { 78 if (savedBytes[0] == 0x1b) { // ESC 79 if ((savedSize == 2 && 80 (savedBytes[1] == 0x28 && 81 input[0] != 'B' && 82 input[0] != 'J' && 83 input[0] != 'I') && 84 (savedBytes[1] == 0x24 && 85 input[0] != '@' && 86 input[0] != 'B')) || 87 ((savedSize == 1) && 88 (input[0] != 0x28 && 89 input[0] != 0x24))) { 90 badInputLength = 0; 91 throw new MalformedInputException(); 92 } 93 if ((inEnd - inOff) == 1 && savedSize == 1 && 94 savedBytes[0] == 0x1b) { 95 savedSize = 2; 96 savedBytes[1] = input[0]; 97 byteOff++; 98 return 0; 99 } 100 } 101 byte[] newBuf = new byte[inEnd - inOff + savedSize]; 102 for (int i = 0; i < savedSize; i++) { 103 newBuf[i] = savedBytes[i]; 104 } 105 System.arraycopy(input, inOff, newBuf, savedSize, inEnd - inOff); 106 byteOff -= savedSize; 107 input = newBuf; 108 inOff = 0; 109 inEnd = newBuf.length; 110 savedSize = 0; 111 } 112 113 charOff = outOff; 114 readOff = inOff; 115 116 while(readOff < inEnd) { 117 int byte1, byte2, byte3; 118 boolean noOutput = false; 119 120 // Is there room in the output buffer for the result? 121 if (charOff >= outEnd) { 122 throw new ConversionBufferFullException(); 123 } 124 125 // Get the input byte 126 byte1 = input[readOff] & 0xFF; 127 inputSize = 1; 128 129 if ((byte1 & (byte)0x80) != 0){ 130 badInputLength = 1; 131 throw new MalformedInputException(); 132 } 133 134 // Is this a escape sequence? 135 while (byte1 == 0x1b || byte1 == 0x0e || byte1 == 0x0f) { 136 if (byte1 == 0x1b){ // ESC 137 if (readOff + inputSize + 1 >= inEnd) { 138 if (readOff + inputSize >= inEnd) { 139 savedSize = 1; 140 savedBytes[0] = (byte)byte1; 141 } else { 142 savedSize = 2; 143 savedBytes[0] = (byte)byte1; 144 savedBytes[1] = input[readOff + inputSize]; 145 inputSize++; 146 } 147 break; 148 } 149 byte2 = input[readOff + inputSize] & 0xFF; 150 inputSize++; 151 if ((byte2 & (byte)0x80) != 0){ 152 badInputLength = 2; 153 throw new MalformedInputException(); 154 } 155 if (byte2 == 0x28){ 156 byte3 = input[readOff + inputSize] & 0xFF; 157 inputSize++; 158 if (byte3 == 'B'){ 159 currentState = ASCII; 160 } else if (byte3 == 'J'){ 161 currentState = JISX0201_1976; 162 } else if (byte3 == 'I'){ 163 currentState = JISX0201_1976_KANA; 164 } else { 165 // illegal ESC sequence 166 badInputLength = 3; 167 throw new MalformedInputException(); 168 } 169 } else if (byte2 == '$'){ 170 byte3 = input[readOff + inputSize] & 0xFF; 171 inputSize++; 172 if ((byte3 & (byte)0x80) != 0){ 173 badInputLength = 3; 174 throw new MalformedInputException(); 175 } 176 if (byte3 == '@'){ 177 currentState = JISX0208_1978; 178 } else if (byte3 == 'B'){ 179 currentState = JISX0208_1983; 180 } else { 181 // illegal ESC sequence 182 badInputLength = 3; 183 throw new MalformedInputException(); 184 } 185 } else { 186 // illegal ESC sequence 187 badInputLength = 2; 188 throw new MalformedInputException(); 189 } 190 if (readOff + inputSize >= inEnd) { 191 noOutput = true; 192 break; 193 } else { 194 byte1 = input[readOff + inputSize]; 195 inputSize++; 196 } 197 } else if (byte1 == 0x0e){ // shift out for one byte kana 198 previousState = currentState; 199 currentState = SHIFTOUT; 200 if (readOff + inputSize >= inEnd) { 201 noOutput = true; 202 break; 203 } 204 byte1 = input[readOff + inputSize]; 205 inputSize++; 206 if ((byte1 & (byte)0x80) != 0){ 207 badInputLength = 1; 208 throw new MalformedInputException(); 209 } 210 } else if (byte1 == 0x0f){ // shift in for previous mode 211 currentState = previousState; 212 if (readOff + inputSize >= inEnd) { 213 noOutput = true; 214 break; 215 } 216 byte1 = input[readOff + inputSize]; 217 inputSize++; 218 if ((byte1 & (byte)0x80) != 0){ 219 badInputLength = 1; 220 throw new MalformedInputException(); 221 } 222 } 223 } 224 if (noOutput || savedSize != 0) { 225 byteOff += inputSize; 226 break; 227 } 228 noOutput = false; 229 switch (currentState){ 230 case ASCII: 231 outputChar = (char)(byte1 & 0xff); 232 break; 233 case JISX0201_1976: 234 switch (byte1) { 235 case 0x5c: 236 outputChar = '\u00a5'; 237 break; 238 case 0x7e: 239 outputChar = '\u203e'; 240 break; 241 default: 242 outputChar = (char)byte1; 243 break; 244 } 245 break; 246 case JISX0208_1978: 247 case JISX0208_1983: 248 if (readOff + inputSize >= inEnd) { 249 savedSize = 1; 250 savedBytes[0] = (byte)byte1; 251 break; 252 } 253 byte2 = input[readOff + inputSize] & 0xff; 254 inputSize++; 255 if ((byte2 & (byte)0x80) != 0){ 256 badInputLength = 1; 257 throw new MalformedInputException(); 258 } 259 // jisx0208Chars table convert FULLWIDTH_REVERSE_SOLIDUS 260 // 0x2140 to REVERSE_SOLIDUS (BACKSLASH) 0x5c. 261 // This behavior causes problem because 262 // 0x5c is special escape character for java. 263 if (byte1 == 0x21 && byte2 == 0x40) { 264 outputChar = '\uFF3C'; 265 } else { 266 try { 267 outputChar = getUnicode(byte1, byte2); 268 } catch (ArrayIndexOutOfBoundsException e) { 269 outputChar = '\uFFFD'; 270 } 271 } 272 break; 273 case JISX0201_1976_KANA: 274 case SHIFTOUT: 275 if (byte1 > 0x60) { 276 badInputLength = 1; 277 throw new MalformedInputException(); 278 } 279 outputChar = (char)(byte1 + 0xff40); 280 break; 281 } 282 283 if (savedSize != 0) { 284 byteOff += inputSize; 285 break; 286 } 287 288 if (outputChar == '\uFFFD') { 289 if (subMode) 290 outputChar = subChars[0]; 291 else { 292 badInputLength = inputSize; 293 throw new UnknownCharacterException(); 294 } 295 } 296 readOff += inputSize; 297 byteOff += inputSize; 298 output[charOff++] = outputChar; 299 } 300 301 return charOff - outOff; 302 } 303 304 public void reset() { 305 byteOff = charOff = 0; 306 currentState = ASCII; 307 savedSize = 0; 308 } 309 310 public String getCharacterEncoding() { 311 return "ISO2022JP"; 312 } 313 }