blob: a702131e793e81d653d481040a07a010d2b7f553 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1996-1997 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.io;
27
28public 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] = (byte)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}