1 /*
   2  * Copyright (c) 2002, 2006, 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 
  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 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) {
 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 
 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 
 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 
 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 }