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 byte[] 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             int index = 0;
431             char        convChar[] = {unicode};
432             byte        convByte[] = new byte[4];
433             int         converted;
434 
435             try{
436                 CharBuffer cc = CharBuffer.wrap(convChar);
437                 ByteBuffer bb = ByteBuffer.wrap(convByte);
438                 ISOEncoder.encode(cc, bb, true);
439                 bb.flip();
440                 converted = bb.remaining();
441             } catch(Exception e) {
442                 return -1;
443             }
444 
445             if (converted == 2) {
446                 if (!SODesDefined) {
447                     newSODesDefined = true;
448                     ebyte[0] = ISO_ESC;
449                     System.arraycopy(SODesig, 0, ebyte, 1, SODesig.length);
450                     index = SODesig.length + 1;
451                 }
452                 if (!shiftout) {
453                     newshiftout = true;
454                     ebyte[index++] = ISO_SO;
455                 }
456                 ebyte[index++] = (byte)(convByte[0] & 0x7f);
457                 ebyte[index++] = (byte)(convByte[1] & 0x7f);
458             } else {
459                 if(convByte[0] == SS2) {
460                     if (convByte[1] == PLANE2) {
461                         if (!SS2DesDefined) {
462                             newSS2DesDefined = true;
463                             ebyte[0] = ISO_ESC;
464                             System.arraycopy(SS2Desig, 0, ebyte, 1, SS2Desig.length);
465                             index = SS2Desig.length + 1;
466                         }
467                         ebyte[index++] = ISO_ESC;
468                         ebyte[index++] = ISO_SS2_7;
469                         ebyte[index++] = (byte)(convByte[2] & 0x7f);
470                         ebyte[index++] = (byte)(convByte[3] & 0x7f);
471                     } else if (convByte[1] == PLANE3) {
472                         if(!SS3DesDefined){
473                             newSS3DesDefined = true;
474                             ebyte[0] = ISO_ESC;
475                             System.arraycopy(SS3Desig, 0, ebyte, 1, SS3Desig.length);
476                             index = SS3Desig.length + 1;
477                         }
478                         ebyte[index++] = ISO_ESC;
479                         ebyte[index++] = ISO_SS3_7;
480                         ebyte[index++] = (byte)(convByte[2] & 0x7f);
481                         ebyte[index++] = (byte)(convByte[3] & 0x7f);
482                     }
483                 }
484             }
485             return index;
486         }
487 
encodeArrayLoop(CharBuffer src, ByteBuffer dst)488         private CoderResult encodeArrayLoop(CharBuffer src,
489                                             ByteBuffer dst)
490         {
491             char[] sa = src.array();
492             int sp = src.arrayOffset() + src.position();
493             int sl = src.arrayOffset() + src.limit();
494             assert (sp <= sl);
495             sp = (sp <= sl ? sp : sl);
496             byte[] da = dst.array();
497             int dp = dst.arrayOffset() + dst.position();
498             int dl = dst.arrayOffset() + dst.limit();
499             assert (dp <= dl);
500             dp = (dp <= dl ? dp : dl);
501 
502             int outputSize = 0;
503             byte[]  outputByte = new byte[8];
504             newshiftout = shiftout;
505             newSODesDefined = SODesDefined;
506             newSS2DesDefined = SS2DesDefined;
507             newSS3DesDefined = SS3DesDefined;
508 
509             try {
510                 while (sp < sl) {
511                     char c = sa[sp];
512                     if (Character.isSurrogate(c)) {
513                         if (sgp.parse(c, sa, sp, sl) < 0)
514                             return sgp.error();
515                         return sgp.unmappableResult();
516                     }
517 
518                     if (c < 0x80) {     // ASCII
519                         if (shiftout){
520                             newshiftout = false;
521                             outputSize = 2;
522                             outputByte[0] = ISO_SI;
523                             outputByte[1] = (byte)(c & 0x7f);
524                         } else {
525                             outputSize = 1;
526                             outputByte[0] = (byte)(c & 0x7f);
527                         }
528                         if(sa[sp] == '\n'){
529                             newSODesDefined = false;
530                             newSS2DesDefined = false;
531                             newSS3DesDefined = false;
532                         }
533                     } else {
534                         outputSize = unicodeToNative(c, outputByte);
535                         if (outputSize == 0) {
536                             return CoderResult.unmappableForLength(1);
537                         }
538                     }
539                     if (dl - dp < outputSize)
540                         return CoderResult.OVERFLOW;
541 
542                     for (int i = 0; i < outputSize; i++)
543                         da[dp++] = outputByte[i];
544                     sp++;
545                     shiftout = newshiftout;
546                     SODesDefined = newSODesDefined;
547                     SS2DesDefined = newSS2DesDefined;
548                     SS3DesDefined = newSS3DesDefined;
549                 }
550                 return CoderResult.UNDERFLOW;
551              } finally {
552                 src.position(sp - src.arrayOffset());
553                 dst.position(dp - dst.arrayOffset());
554              }
555         }
556 
encodeBufferLoop(CharBuffer src, ByteBuffer dst)557         private CoderResult encodeBufferLoop(CharBuffer src,
558                                              ByteBuffer dst)
559         {
560             int outputSize = 0;
561             byte[]  outputByte = new byte[8];
562             int     inputSize = 0;                 // Size of input
563             newshiftout = shiftout;
564             newSODesDefined = SODesDefined;
565             newSS2DesDefined = SS2DesDefined;
566             newSS3DesDefined = SS3DesDefined;
567             int mark = src.position();
568 
569             try {
570                 while (src.hasRemaining()) {
571                     char inputChar = src.get();
572                     if (Character.isSurrogate(inputChar)) {
573                         if (sgp.parse(inputChar, src) < 0)
574                             return sgp.error();
575                         return sgp.unmappableResult();
576                     }
577                     if (inputChar < 0x80) {     // ASCII
578                         if (shiftout){
579                             newshiftout = false;
580                             outputSize = 2;
581                             outputByte[0] = ISO_SI;
582                             outputByte[1] = (byte)(inputChar & 0x7f);
583                         } else {
584                             outputSize = 1;
585                             outputByte[0] = (byte)(inputChar & 0x7f);
586                         }
587                         if(inputChar == '\n'){
588                             newSODesDefined = false;
589                             newSS2DesDefined = false;
590                             newSS3DesDefined = false;
591                         }
592                     } else {
593                         outputSize = unicodeToNative(inputChar, outputByte);
594                         if (outputSize == 0) {
595                             return CoderResult.unmappableForLength(1);
596                         }
597                     }
598 
599                     if (dst.remaining() < outputSize)
600                         return CoderResult.OVERFLOW;
601                     for (int i = 0; i < outputSize; i++)
602                         dst.put(outputByte[i]);
603                     mark++;
604                     shiftout = newshiftout;
605                     SODesDefined = newSODesDefined;
606                     SS2DesDefined = newSS2DesDefined;
607                     SS3DesDefined = newSS3DesDefined;
608                 }
609                 return CoderResult.UNDERFLOW;
610             } finally {
611                 src.position(mark);
612             }
613         }
614 
encodeLoop(CharBuffer src, ByteBuffer dst)615         protected CoderResult encodeLoop(CharBuffer src,
616                                          ByteBuffer dst)
617         {
618             if (src.hasArray() && dst.hasArray())
619                 return encodeArrayLoop(src, dst);
620             else
621                 return encodeBufferLoop(src, dst);
622         }
623     }
624 }
625