1 /*
2  * Copyright (c) 2002, 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 /*
27  */
28 
29 package sun.nio.cs.ext;
30 
31 import java.nio.ByteBuffer;
32 import java.nio.CharBuffer;
33 import java.nio.charset.Charset;
34 import java.nio.charset.CharsetDecoder;
35 import java.nio.charset.CharsetEncoder;
36 import java.nio.charset.CoderResult;
37 import sun.nio.cs.Surrogate;
38 
39 abstract 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 
ISO2022(String csname, String[] aliases)52     public ISO2022(String csname, String[] aliases) {
53         super(csname, aliases);
54     }
55 
newDecoder()56     public CharsetDecoder newDecoder() {
57         return new Decoder(this);
58     }
59 
newEncoder()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 
Decoder(Charset cs)83         protected Decoder(Charset cs) {
84             super(cs, 1.0f, 1.0f);
85         }
86 
implReset()87         protected void implReset() {
88             curSODes = 0;
89             curSS2Des = 0;
90             curSS3Des = 0;
91             shiftout = false;
92         }
93 
decode(byte byte1, byte byte2, byte shiftFlag)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 = SODecoder;
108                 break;
109             case SS2Flag:
110                 tmpIndex = curSS2Des;
111                 tmpDecoder = SS2Decoder;
112                 break;
113             case SS3Flag:
114                 tmpIndex = curSS3Des;
115                 tmpDecoder = 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 
findDesig(byte[] in, int sp, int sl, byte[][] desigs)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 
findDesigBuf(ByteBuffer in, byte[][] desigs)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 
decodeArrayLoop(ByteBuffer src, CharBuffer dst)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 
decodeBufferLoop(ByteBuffer src, CharBuffer dst)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 
decodeLoop(ByteBuffer src, CharBuffer dst)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         public static final byte SS2 = (byte)0x8e;
392         public static final byte PLANE2 = (byte)0xA2;
393         public static final byte PLANE3 = (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 
Encoder(Charset cs)414         protected Encoder(Charset cs) {
415             super(cs, 4.0f, 8.0f);
416         }
417 
canEncode(char c)418         public boolean canEncode(char c) {
419             return (ISOEncoder.canEncode(c));
420         }
421 
implReset()422         protected void implReset() {
423             shiftout = false;
424             SODesDefined = false;
425             SS2DesDefined = false;
426             SS3DesDefined = false;
427         }
428 
unicodeToNative(char unicode, byte ebyte[])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) {
464                     if (convByte[1] == PLANE2) {
465                         if (!SS2DesDefined) {
466                             newSS2DesDefined = true;
467                             ebyte[0] = ISO_ESC;
468                             tmpByte = SS2Desig.getBytes();
469                             System.arraycopy(tmpByte, 0, ebyte, 1, tmpByte.length);
470                             index = tmpByte.length+1;
471                         }
472                         ebyte[index++] = ISO_ESC;
473                         ebyte[index++] = ISO_SS2_7;
474                         ebyte[index++] = (byte)(convByte[2] & 0x7f);
475                         ebyte[index++] = (byte)(convByte[3] & 0x7f);
476                     } else if (convByte[1] == PLANE3) {
477                         if(!SS3DesDefined){
478                             newSS3DesDefined = true;
479                             ebyte[0] = ISO_ESC;
480                             tmpByte = SS3Desig.getBytes();
481                             System.arraycopy(tmpByte, 0, ebyte, 1, tmpByte.length);
482                             index = tmpByte.length+1;
483                         }
484                         ebyte[index++] = ISO_ESC;
485                         ebyte[index++] = ISO_SS3_7;
486                         ebyte[index++] = (byte)(convByte[2] & 0x7f);
487                         ebyte[index++] = (byte)(convByte[3] & 0x7f);
488                     }
489                 }
490             }
491             return index;
492         }
493 
encodeArrayLoop(CharBuffer src, ByteBuffer dst)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 (Character.isSurrogate(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 
encodeBufferLoop(CharBuffer src, ByteBuffer dst)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 (Character.isSurrogate(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 
encodeLoop(CharBuffer src, ByteBuffer dst)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 }
632