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
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 = 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
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        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
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            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
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
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
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