blob: 9d35a7a79f521247c9e692cf6d3e32abe6e1ec56 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2002-2006 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
26/*
27 */
28
29package sun.nio.cs.ext;
30
31import java.nio.ByteBuffer;
32import java.nio.CharBuffer;
33import java.nio.charset.Charset;
34import java.nio.charset.CharsetDecoder;
35import java.nio.charset.CharsetEncoder;
36import java.nio.charset.CoderResult;
37import sun.nio.cs.Surrogate;
38
39abstract class ISO2022
40 extends Charset
41{
42
43 private static final byte ISO_ESC = 0x1b;
44 private static final byte ISO_SI = 0x0f;
45 private static final byte ISO_SO = 0x0e;
46 private static final byte ISO_SS2_7 = 0x4e;
47 private static final byte ISO_SS3_7 = 0x4f;
48 private static final byte MSB = (byte)0x80;
49 private static final char REPLACE_CHAR = '\uFFFD';
50 private static final byte minDesignatorLength = 3;
51
52 public ISO2022(String csname, String[] aliases) {
53 super(csname, aliases);
54 }
55
56 public CharsetDecoder newDecoder() {
57 return new Decoder(this);
58 }
59
60 public CharsetEncoder newEncoder() {
61 return new Encoder(this);
62 }
63
64 protected static class Decoder extends CharsetDecoder {
65
66 // Value to be filled by subclass
67 protected byte SODesig[][];
68 protected byte SS2Desig[][] = null;
69 protected byte SS3Desig[][] = null;
70
71 protected CharsetDecoder SODecoder[];
72 protected CharsetDecoder SS2Decoder[] = null;
73 protected CharsetDecoder SS3Decoder[] = null;
74
75 private static final byte SOFlag = 0;
76 private static final byte SS2Flag = 1;
77 private static final byte SS3Flag = 2;
78
79 private int curSODes, curSS2Des, curSS3Des;
80 private boolean shiftout;
81 private CharsetDecoder tmpDecoder[];
82
83 protected Decoder(Charset cs) {
84 super(cs, 1.0f, 1.0f);
85 }
86
87 protected void implReset() {
88 curSODes = 0;
89 curSS2Des = 0;
90 curSS3Des = 0;
91 shiftout = false;
92 }
93
94 private char decode(byte byte1, byte byte2, byte shiftFlag)
95 {
96 byte1 |= MSB;
97 byte2 |= MSB;
98
99 byte[] tmpByte = { byte1,byte2 };
100 char[] tmpChar = new char[1];
101 int i = 0,
102 tmpIndex = 0;
103
104 switch(shiftFlag) {
105 case SOFlag:
106 tmpIndex = curSODes;
107 tmpDecoder = (CharsetDecoder [])SODecoder;
108 break;
109 case SS2Flag:
110 tmpIndex = curSS2Des;
111 tmpDecoder = (CharsetDecoder [])SS2Decoder;
112 break;
113 case SS3Flag:
114 tmpIndex = curSS3Des;
115 tmpDecoder = (CharsetDecoder [])SS3Decoder;
116 break;
117 }
118
119 if (tmpDecoder != null) {
120 for(i = 0; i < tmpDecoder.length; i++) {
121 if(tmpIndex == i) {
122 try {
123 ByteBuffer bb = ByteBuffer.wrap(tmpByte,0,2);
124 CharBuffer cc = CharBuffer.wrap(tmpChar,0,1);
125 tmpDecoder[i].decode(bb, cc, true);
126 cc.flip();
127 return cc.get();
128 } catch (Exception e) {}
129 }
130 }
131 }
132 return REPLACE_CHAR;
133 }
134
135 private int findDesig(byte[] in, int sp, int sl, byte[][] desigs) {
136 if (desigs == null) return -1;
137 int i = 0;
138 while (i < desigs.length) {
139 if (desigs[i] != null && sl - sp >= desigs[i].length) {
140 int j = 0;
141 while (j < desigs[i].length && in[sp+j] == desigs[i][j]) { j++; }
142 if (j == desigs[i].length)
143 return i;
144 }
145 i++;
146 }
147 return -1;
148 }
149
150 private int findDesigBuf(ByteBuffer in, byte[][] desigs) {
151 if (desigs == null) return -1;
152 int i = 0;
153 while (i < desigs.length) {
154 if (desigs[i] != null && in.remaining() >= desigs[i].length) {
155 int j = 0;
156 in.mark();
157 while (j < desigs[i].length && in.get() == desigs[i][j]) { j++; }
158 if (j == desigs[i].length)
159 return i;
160 in.reset();
161 }
162 i++;
163 }
164 return -1;
165 }
166
167 private CoderResult decodeArrayLoop(ByteBuffer src,
168 CharBuffer dst)
169 {
170 byte[] sa = src.array();
171 int sp = src.arrayOffset() + src.position();
172 int sl = src.arrayOffset() + src.limit();
173 assert (sp <= sl);
174 sp = (sp <= sl ? sp : sl);
175
176 char[] da = dst.array();
177 int dp = dst.arrayOffset() + dst.position();
178 int dl = dst.arrayOffset() + dst.limit();
179 assert (dp <= dl);
180 dp = (dp <= dl ? dp : dl);
181
182 int b1 = 0, b2 = 0, b3 = 0;
183
184 try {
185 while (sp < sl) {
186 b1 = sa[sp] & 0xff;
187 int inputSize = 1;
188 switch (b1) {
189 case ISO_SO:
190 shiftout = true;
191 inputSize = 1;
192 break;
193 case ISO_SI:
194 shiftout = false;
195 inputSize = 1;
196 break;
197 case ISO_ESC:
198 if (sl - sp - 1 < minDesignatorLength)
199 return CoderResult.UNDERFLOW;
200
201 int desig = findDesig(sa, sp + 1, sl, SODesig);
202 if (desig != -1) {
203 curSODes = desig;
204 inputSize = SODesig[desig].length + 1;
205 break;
206 }
207 desig = findDesig(sa, sp + 1, sl, SS2Desig);
208 if (desig != -1) {
209 curSS2Des = desig;
210 inputSize = SS2Desig[desig].length + 1;
211 break;
212 }
213 desig = findDesig(sa, sp + 1, sl, SS3Desig);
214 if (desig != -1) {
215 curSS3Des = desig;
216 inputSize = SS3Desig[desig].length + 1;
217 break;
218 }
219 if (sl - sp < 2)
220 return CoderResult.UNDERFLOW;
221 b1 = sa[sp + 1];
222 switch(b1) {
223 case ISO_SS2_7:
224 if (sl - sp < 4)
225 return CoderResult.UNDERFLOW;
226 b2 = sa[sp +2];
227 b3 = sa[sp +3];
228 if (dl - dp <1)
229 return CoderResult.OVERFLOW;
230 da[dp] = decode((byte)b2,
231 (byte)b3,
232 SS2Flag);
233 dp++;
234 inputSize = 4;
235 break;
236 case ISO_SS3_7:
237 if (sl - sp < 4)
238 return CoderResult.UNDERFLOW;
239 b2 = sa[sp + 2];
240 b3 = sa[sp + 3];
241 if (dl - dp <1)
242 return CoderResult.OVERFLOW;
243 da[dp] = decode((byte)b2,
244 (byte)b3,
245 SS3Flag);
246 dp++;
247 inputSize = 4;
248 break;
249 default:
250 return CoderResult.malformedForLength(2);
251 }
252 break;
253 default:
254 if (dl - dp < 1)
255 return CoderResult.OVERFLOW;
256 if (!shiftout) {
257 da[dp++]=(char)(sa[sp] & 0xff);
258 } else {
259 if (dl - dp < 1)
260 return CoderResult.OVERFLOW;
261 if (sl - sp < 2)
262 return CoderResult.UNDERFLOW;
263 b2 = sa[sp+1] & 0xff;
264 da[dp++] = decode((byte)b1,
265 (byte)b2,
266 SOFlag);
267 inputSize = 2;
268 }
269 break;
270 }
271 sp += inputSize;
272 }
273 return CoderResult.UNDERFLOW;
274 } finally {
275 src.position(sp - src.arrayOffset());
276 dst.position(dp - dst.arrayOffset());
277 }
278 }
279
280 private CoderResult decodeBufferLoop(ByteBuffer src,
281 CharBuffer dst)
282 {
283 int mark = src.position();
284 int b1 = 0, b2 = 0, b3 = 0;
285
286 try {
287 while (src.hasRemaining()) {
288 b1 = src.get();
289 int inputSize = 1;
290 switch (b1) {
291 case ISO_SO:
292 shiftout = true;
293 break;
294 case ISO_SI:
295 shiftout = false;
296 break;
297 case ISO_ESC:
298 if (src.remaining() < minDesignatorLength)
299 return CoderResult.UNDERFLOW;
300
301 int desig = findDesigBuf(src, SODesig);
302 if (desig != -1) {
303 curSODes = desig;
304 inputSize = SODesig[desig].length + 1;
305 break;
306 }
307 desig = findDesigBuf(src, SS2Desig);
308 if (desig != -1) {
309 curSS2Des = desig;
310 inputSize = SS2Desig[desig].length + 1;
311 break;
312 }
313 desig = findDesigBuf(src, SS3Desig);
314 if (desig != -1) {
315 curSS3Des = desig;
316 inputSize = SS3Desig[desig].length + 1;
317 break;
318 }
319
320 if (src.remaining() < 1)
321 return CoderResult.UNDERFLOW;
322 b1 = src.get();
323 switch(b1) {
324 case ISO_SS2_7:
325 if (src.remaining() < 2)
326 return CoderResult.UNDERFLOW;
327 b2 = src.get();
328 b3 = src.get();
329 if (dst.remaining() < 1)
330 return CoderResult.OVERFLOW;
331 dst.put(decode((byte)b2,
332 (byte)b3,
333 SS2Flag));
334 inputSize = 4;
335 break;
336 case ISO_SS3_7:
337 if (src.remaining() < 2)
338 return CoderResult.UNDERFLOW;
339 b2 = src.get();
340 b3 = src.get();
341 if (dst.remaining() < 1)
342 return CoderResult.OVERFLOW;
343 dst.put(decode((byte)b2,
344 (byte)b3,
345 SS3Flag));
346 inputSize = 4;
347 break;
348 default:
349 return CoderResult.malformedForLength(2);
350 }
351 break;
352 default:
353 if (dst.remaining() < 1)
354 return CoderResult.OVERFLOW;
355 if (!shiftout) {
356 dst.put((char)(b1 & 0xff));
357 } else {
358 if (dst.remaining() < 1)
359 return CoderResult.OVERFLOW;
360 if (src.remaining() < 1)
361 return CoderResult.UNDERFLOW;
362 b2 = src.get() & 0xff;
363 dst.put(decode((byte)b1,
364 (byte)b2,
365 SOFlag));
366 inputSize = 2;
367 }
368 break;
369 }
370 mark += inputSize;
371 }
372 return CoderResult.UNDERFLOW;
373 } catch (Exception e) { e.printStackTrace(); return CoderResult.OVERFLOW; }
374 finally {
375 src.position(mark);
376 }
377 }
378
379 protected CoderResult decodeLoop(ByteBuffer src,
380 CharBuffer dst)
381 {
382 if (src.hasArray() && dst.hasArray())
383 return decodeArrayLoop(src, dst);
384 else
385 return decodeBufferLoop(src, dst);
386 }
387 }
388
389 protected static class Encoder extends CharsetEncoder {
390 private final Surrogate.Parser sgp = new Surrogate.Parser();
391 private final byte SS2 = (byte)0x8e;
392 private final byte P2 = (byte)0xA2;
393 private final byte P3 = (byte)0xA3;
394 private final byte MSB = (byte)0x80;
395
396 protected final byte maximumDesignatorLength = 4;
397
398 protected String SODesig,
399 SS2Desig = null,
400 SS3Desig = null;
401
402 protected CharsetEncoder ISOEncoder;
403
404 private boolean shiftout = false;
405 private boolean SODesDefined = false;
406 private boolean SS2DesDefined = false;
407 private boolean SS3DesDefined = false;
408
409 private boolean newshiftout = false;
410 private boolean newSODesDefined = false;
411 private boolean newSS2DesDefined = false;
412 private boolean newSS3DesDefined = false;
413
414 protected Encoder(Charset cs) {
415 super(cs, 4.0f, 8.0f);
416 }
417
418 public boolean canEncode(char c) {
419 return (ISOEncoder.canEncode(c));
420 }
421
422 protected void implReset() {
423 shiftout = false;
424 SODesDefined = false;
425 SS2DesDefined = false;
426 SS3DesDefined = false;
427 }
428
429 private int unicodeToNative(char unicode, byte ebyte[])
430 {
431 int index = 0;
432 byte tmpByte[];
433 char convChar[] = {unicode};
434 byte convByte[] = new byte[4];
435 int converted;
436
437 try{
438 CharBuffer cc = CharBuffer.wrap(convChar);
439 ByteBuffer bb = ByteBuffer.allocate(4);
440 ISOEncoder.encode(cc, bb, true);
441 bb.flip();
442 converted = bb.remaining();
443 bb.get(convByte,0,converted);
444 } catch(Exception e) {
445 return -1;
446 }
447
448 if (converted == 2) {
449 if (!SODesDefined) {
450 newSODesDefined = true;
451 ebyte[0] = ISO_ESC;
452 tmpByte = SODesig.getBytes();
453 System.arraycopy(tmpByte,0,ebyte,1,tmpByte.length);
454 index = tmpByte.length+1;
455 }
456 if (!shiftout) {
457 newshiftout = true;
458 ebyte[index++] = ISO_SO;
459 }
460 ebyte[index++] = (byte)(convByte[0] & 0x7f);
461 ebyte[index++] = (byte)(convByte[1] & 0x7f);
462 } else {
463 if((convByte[0] == SS2) && (convByte[1] == P2)) {
464 if (!SS2DesDefined) {
465 newSS2DesDefined = true;
466 ebyte[0] = ISO_ESC;
467 tmpByte = SS2Desig.getBytes();
468 System.arraycopy(tmpByte, 0, ebyte, 1, tmpByte.length);
469 index = tmpByte.length+1;
470 }
471 ebyte[index++] = ISO_ESC;
472 ebyte[index++] = ISO_SS2_7;
473 ebyte[index++] = (byte)(convByte[2] & 0x7f);
474 ebyte[index++] = (byte)(convByte[3] & 0x7f);
475 }
476 if((convByte[0] == SS2)&&(convByte[1] == 0xA3))
477 {
478 if(!SS3DesDefined){
479 newSS3DesDefined = true;
480 ebyte[0] = ISO_ESC;
481 tmpByte = SS3Desig.getBytes();
482 System.arraycopy(tmpByte, 0, ebyte, 1, tmpByte.length);
483 index = tmpByte.length+1;
484 }
485 ebyte[index++] = ISO_ESC;
486 ebyte[index++] = ISO_SS3_7;
487 ebyte[index++] = (byte)(convByte[2] & 0x7f);
488 ebyte[index++] = (byte)(convByte[3] & 0x7f);
489 }
490 }
491 return index;
492 }
493
494 private CoderResult encodeArrayLoop(CharBuffer src,
495 ByteBuffer dst)
496 {
497 char[] sa = src.array();
498 int sp = src.arrayOffset() + src.position();
499 int sl = src.arrayOffset() + src.limit();
500 assert (sp <= sl);
501 sp = (sp <= sl ? sp : sl);
502 byte[] da = dst.array();
503 int dp = dst.arrayOffset() + dst.position();
504 int dl = dst.arrayOffset() + dst.limit();
505 assert (dp <= dl);
506 dp = (dp <= dl ? dp : dl);
507
508 int outputSize = 0;
509 byte[] outputByte = new byte[8];
510 newshiftout = shiftout;
511 newSODesDefined = SODesDefined;
512 newSS2DesDefined = SS2DesDefined;
513 newSS3DesDefined = SS3DesDefined;
514
515 try {
516 while (sp < sl) {
517 char c = sa[sp];
518 if (Surrogate.is(c)) {
519 if (sgp.parse(c, sa, sp, sl) < 0)
520 return sgp.error();
521 return sgp.unmappableResult();
522 }
523
524 if (c < 0x80) { // ASCII
525 if (shiftout){
526 newshiftout = false;
527 outputSize = 2;
528 outputByte[0] = ISO_SI;
529 outputByte[1] = (byte)(c & 0x7f);
530 } else {
531 outputSize = 1;
532 outputByte[0] = (byte)(c & 0x7f);
533 }
534 if(sa[sp] == '\n'){
535 newSODesDefined = false;
536 newSS2DesDefined = false;
537 newSS3DesDefined = false;
538 }
539 } else {
540 outputSize = unicodeToNative(c, outputByte);
541 if (outputSize == 0) {
542 return CoderResult.unmappableForLength(1);
543 }
544 }
545 if (dl - dp < outputSize)
546 return CoderResult.OVERFLOW;
547
548 for (int i = 0; i < outputSize; i++)
549 da[dp++] = outputByte[i];
550 sp++;
551 shiftout = newshiftout;
552 SODesDefined = newSODesDefined;
553 SS2DesDefined = newSS2DesDefined;
554 SS3DesDefined = newSS3DesDefined;
555 }
556 return CoderResult.UNDERFLOW;
557 } finally {
558 src.position(sp - src.arrayOffset());
559 dst.position(dp - dst.arrayOffset());
560 }
561 }
562
563
564 private CoderResult encodeBufferLoop(CharBuffer src,
565 ByteBuffer dst)
566 {
567 int outputSize = 0;
568 byte[] outputByte = new byte[8];
569 int inputSize = 0; // Size of input
570 newshiftout = shiftout;
571 newSODesDefined = SODesDefined;
572 newSS2DesDefined = SS2DesDefined;
573 newSS3DesDefined = SS3DesDefined;
574 int mark = src.position();
575
576 try {
577 while (src.hasRemaining()) {
578 char inputChar = src.get();
579 if (Surrogate.is(inputChar)) {
580 if (sgp.parse(inputChar, src) < 0)
581 return sgp.error();
582 return sgp.unmappableResult();
583 }
584 if (inputChar < 0x80) { // ASCII
585 if (shiftout){
586 newshiftout = false;
587 outputSize = 2;
588 outputByte[0] = ISO_SI;
589 outputByte[1] = (byte)(inputChar & 0x7f);
590 } else {
591 outputSize = 1;
592 outputByte[0] = (byte)(inputChar & 0x7f);
593 }
594 if(inputChar == '\n'){
595 newSODesDefined = false;
596 newSS2DesDefined = false;
597 newSS3DesDefined = false;
598 }
599 } else {
600 outputSize = unicodeToNative(inputChar, outputByte);
601 if (outputSize == 0) {
602 return CoderResult.unmappableForLength(1);
603 }
604 }
605
606 if (dst.remaining() < outputSize)
607 return CoderResult.OVERFLOW;
608 for (int i = 0; i < outputSize; i++)
609 dst.put(outputByte[i]);
610 mark++;
611 shiftout = newshiftout;
612 SODesDefined = newSODesDefined;
613 SS2DesDefined = newSS2DesDefined;
614 SS3DesDefined = newSS3DesDefined;
615 }
616 return CoderResult.UNDERFLOW;
617 } finally {
618 src.position(mark);
619 }
620 }
621
622 protected CoderResult encodeLoop(CharBuffer src,
623 ByteBuffer dst)
624 {
625 if (src.hasArray() && dst.hasArray())
626 return encodeArrayLoop(src, dst);
627 else
628 return encodeBufferLoop(src, dst);
629 }
630 }
631}