1 /*
   2  * Copyright 2002-2006 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 /*
  27  */
  28 
  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 = (CharsetDecoder [])SODecoder;
 108                 break;
 109             case SS2Flag:
 110                 tmpIndex = curSS2Des;
 111                 tmpDecoder = (CharsetDecoder [])SS2Decoder;
 112                 break;
 113             case SS3Flag:
 114                 tmpIndex = curSS3Des;
 115                 tmpDecoder = (CharsetDecoder [])SS3Decoder;
 116                 break;
 117             }
 118 
 119             if (tmpDecoder != null) {
 120                 for(i = 0; i < tmpDecoder.length; i++) {
 121                     if(tmpIndex == i) {
 122                         try {
 123                             ByteBuffer bb = ByteBuffer.wrap(tmpByte,0,2);
 124                             CharBuffer cc = CharBuffer.wrap(tmpChar,0,1);
 125                             tmpDecoder[i].decode(bb, cc, true);
 126                             cc.flip();
 127                             return cc.get();
 128                         } catch (Exception e) {}
 129                     }
 130                 }
 131             }
 132             return REPLACE_CHAR;
 133         }
 134 
 135         private int findDesig(byte[] in, int sp, int sl, byte[][] desigs) {
 136             if (desigs == null) return -1;
 137             int i = 0;
 138             while (i < desigs.length) {
 139                 if (desigs[i] != null && sl - sp >= desigs[i].length) {
 140                     int j = 0;
 141                     while (j < desigs[i].length && in[sp+j] == desigs[i][j]) { j++; }
 142                     if (j == desigs[i].length)
 143                         return i;
 144                 }
 145                 i++;
 146             }
 147             return -1;
 148         }
 149 
 150         private int findDesigBuf(ByteBuffer in, byte[][] desigs) {
 151             if (desigs == null) return -1;
 152             int i = 0;
 153             while (i < desigs.length) {
 154                 if (desigs[i] != null && in.remaining() >= desigs[i].length) {
 155                     int j = 0;
 156                     in.mark();
 157                     while (j < desigs[i].length && in.get() == desigs[i][j]) { j++; }
 158                     if (j == desigs[i].length)
 159                         return i;
 160                     in.reset();
 161                 }
 162                 i++;
 163             }
 164             return -1;
 165         }
 166 
 167         private CoderResult decodeArrayLoop(ByteBuffer src,
 168                                             CharBuffer dst)
 169         {
 170             byte[] sa = src.array();
 171             int sp = src.arrayOffset() + src.position();
 172             int sl = src.arrayOffset() + src.limit();
 173             assert (sp <= sl);
 174             sp = (sp <= sl ? sp : sl);
 175 
 176             char[] da = dst.array();
 177             int dp = dst.arrayOffset() + dst.position();
 178             int dl = dst.arrayOffset() + dst.limit();
 179             assert (dp <= dl);
 180             dp = (dp <= dl ? dp : dl);
 181 
 182             int b1 = 0, b2 = 0, b3 = 0;
 183 
 184             try {
 185                 while (sp < sl) {
 186                     b1 = sa[sp] & 0xff;
 187                     int inputSize = 1;
 188                     switch (b1) {
 189                         case ISO_SO:
 190                             shiftout = true;
 191                             inputSize = 1;
 192                             break;
 193                         case ISO_SI:
 194                             shiftout = false;
 195                             inputSize = 1;
 196                             break;
 197                         case ISO_ESC:
 198                             if (sl - sp - 1 < minDesignatorLength)
 199                                 return CoderResult.UNDERFLOW;
 200 
 201                             int desig = findDesig(sa, sp + 1, sl, SODesig);
 202                             if (desig != -1) {
 203                                 curSODes = desig;
 204                                 inputSize = SODesig[desig].length + 1;
 205                                 break;
 206                             }
 207                             desig = findDesig(sa, sp + 1, sl, SS2Desig);
 208                             if (desig != -1) {
 209                                 curSS2Des = desig;
 210                                 inputSize = SS2Desig[desig].length + 1;
 211                                 break;
 212                             }
 213                             desig = findDesig(sa, sp + 1, sl, SS3Desig);
 214                             if (desig != -1) {
 215                                 curSS3Des = desig;
 216                                 inputSize = SS3Desig[desig].length + 1;
 217                                 break;
 218                             }
 219                             if (sl - sp < 2)
 220                                 return CoderResult.UNDERFLOW;
 221                             b1 = sa[sp + 1];
 222                             switch(b1) {
 223                             case ISO_SS2_7:
 224                                 if (sl - sp < 4)
 225                                     return CoderResult.UNDERFLOW;
 226                                 b2 = sa[sp +2];
 227                                 b3 = sa[sp +3];
 228                                 if (dl - dp <1)
 229                                     return CoderResult.OVERFLOW;
 230                                 da[dp] = decode((byte)b2,
 231                                                 (byte)b3,
 232                                                 SS2Flag);
 233                                 dp++;
 234                                 inputSize = 4;
 235                                 break;
 236                             case ISO_SS3_7:
 237                                 if (sl - sp < 4)
 238                                     return CoderResult.UNDERFLOW;
 239                                 b2 = sa[sp + 2];
 240                                 b3 = sa[sp + 3];
 241                                 if (dl - dp <1)
 242                                     return CoderResult.OVERFLOW;
 243                                 da[dp] = decode((byte)b2,
 244                                                 (byte)b3,
 245                                                 SS3Flag);
 246                                 dp++;
 247                                 inputSize = 4;
 248                                 break;
 249                             default:
 250                                 return CoderResult.malformedForLength(2);
 251                             }
 252                             break;
 253                         default:
 254                             if (dl - dp < 1)
 255                                 return CoderResult.OVERFLOW;
 256                             if (!shiftout) {
 257                                 da[dp++]=(char)(sa[sp] & 0xff);
 258                             } else {
 259                                 if (dl - dp < 1)
 260                                     return CoderResult.OVERFLOW;
 261                                 if (sl - sp < 2)
 262                                     return CoderResult.UNDERFLOW;
 263                                 b2 = sa[sp+1] & 0xff;
 264                                 da[dp++] = decode((byte)b1,
 265                                                   (byte)b2,
 266                                                    SOFlag);
 267                                 inputSize = 2;
 268                             }
 269                             break;
 270                     }
 271                     sp += inputSize;
 272                 }
 273                 return CoderResult.UNDERFLOW;
 274             } finally {
 275                 src.position(sp - src.arrayOffset());
 276                 dst.position(dp - dst.arrayOffset());
 277             }
 278         }
 279 
 280         private CoderResult decodeBufferLoop(ByteBuffer src,
 281                                              CharBuffer dst)
 282         {
 283             int mark = src.position();
 284             int b1 = 0, b2 = 0, b3 = 0;
 285 
 286             try {
 287                 while (src.hasRemaining()) {
 288                     b1 = src.get();
 289                     int inputSize = 1;
 290                     switch (b1) {
 291                         case ISO_SO:
 292                             shiftout = true;
 293                             break;
 294                         case ISO_SI:
 295                             shiftout = false;
 296                             break;
 297                         case ISO_ESC:
 298                             if (src.remaining() < minDesignatorLength)
 299                                 return CoderResult.UNDERFLOW;
 300 
 301                             int desig = findDesigBuf(src, SODesig);
 302                             if (desig != -1) {
 303                                 curSODes = desig;
 304                                 inputSize = SODesig[desig].length + 1;
 305                                 break;
 306                             }
 307                             desig = findDesigBuf(src, SS2Desig);
 308                             if (desig != -1) {
 309                                 curSS2Des = desig;
 310                                 inputSize = SS2Desig[desig].length + 1;
 311                                 break;
 312                             }
 313                             desig = findDesigBuf(src, SS3Desig);
 314                             if (desig != -1) {
 315                                 curSS3Des = desig;
 316                                 inputSize = SS3Desig[desig].length + 1;
 317                                 break;
 318                             }
 319 
 320                             if (src.remaining() < 1)
 321                                 return CoderResult.UNDERFLOW;
 322                             b1 = src.get();
 323                             switch(b1) {
 324                                 case ISO_SS2_7:
 325                                     if (src.remaining() < 2)
 326                                         return CoderResult.UNDERFLOW;
 327                                     b2 = src.get();
 328                                     b3 = src.get();
 329                                     if (dst.remaining() < 1)
 330                                         return CoderResult.OVERFLOW;
 331                                     dst.put(decode((byte)b2,
 332                                                    (byte)b3,
 333                                                    SS2Flag));
 334                                     inputSize = 4;
 335                                     break;
 336                                 case ISO_SS3_7:
 337                                     if (src.remaining() < 2)
 338                                         return CoderResult.UNDERFLOW;
 339                                     b2 = src.get();
 340                                     b3 = src.get();
 341                                     if (dst.remaining() < 1)
 342                                         return CoderResult.OVERFLOW;
 343                                     dst.put(decode((byte)b2,
 344                                                    (byte)b3,
 345                                                    SS3Flag));
 346                                     inputSize = 4;
 347                                     break;
 348                                 default:
 349                                     return CoderResult.malformedForLength(2);
 350                             }
 351                             break;
 352                         default:
 353                             if (dst.remaining() < 1)
 354                                 return CoderResult.OVERFLOW;
 355                             if (!shiftout) {
 356                                 dst.put((char)(b1 & 0xff));
 357                             } else {
 358                                 if (dst.remaining() < 1)
 359                                     return CoderResult.OVERFLOW;
 360                                 if (src.remaining() < 1)
 361                                     return CoderResult.UNDERFLOW;
 362                                 b2 = src.get() & 0xff;
 363                                 dst.put(decode((byte)b1,
 364                                                       (byte)b2,
 365                                                         SOFlag));
 366                                 inputSize = 2;
 367                             }
 368                             break;
 369                     }
 370                     mark += inputSize;
 371                 }
 372                 return CoderResult.UNDERFLOW;
 373             } catch (Exception e) { e.printStackTrace(); return CoderResult.OVERFLOW; }
 374             finally {
 375                 src.position(mark);
 376             }
 377         }
 378 
 379         protected CoderResult decodeLoop(ByteBuffer src,
 380                                          CharBuffer dst)
 381         {
 382             if (src.hasArray() && dst.hasArray())
 383                 return decodeArrayLoop(src, dst);
 384             else
 385                 return decodeBufferLoop(src, dst);
 386         }
 387     }
 388 
 389     protected static class Encoder extends CharsetEncoder {
 390         private final Surrogate.Parser sgp = new Surrogate.Parser();
 391         private final byte SS2 = (byte)0x8e;
 392         private final byte P2 = (byte)0xA2;
 393         private final byte P3 = (byte)0xA3;
 394         private final byte MSB = (byte)0x80;
 395 
 396         protected final byte maximumDesignatorLength = 4;
 397 
 398         protected String SODesig,
 399                          SS2Desig = null,
 400                          SS3Desig = null;
 401 
 402         protected CharsetEncoder ISOEncoder;
 403 
 404         private boolean shiftout = false;
 405         private boolean SODesDefined = false;
 406         private boolean SS2DesDefined = false;
 407         private boolean SS3DesDefined = false;
 408 
 409         private boolean newshiftout = false;
 410         private boolean newSODesDefined = false;
 411         private boolean newSS2DesDefined = false;
 412         private boolean newSS3DesDefined = false;
 413 
 414         protected Encoder(Charset cs) {
 415             super(cs, 4.0f, 8.0f);
 416         }
 417 
 418         public boolean canEncode(char c) {
 419             return (ISOEncoder.canEncode(c));
 420         }
 421 
 422         protected void implReset() {
 423             shiftout = false;
 424             SODesDefined = false;
 425             SS2DesDefined = false;
 426             SS3DesDefined = false;
 427         }
 428 
 429         private int unicodeToNative(char unicode, byte ebyte[])
 430         {
 431             int index = 0;
 432             byte        tmpByte[];
 433             char        convChar[] = {unicode};
 434             byte        convByte[] = new byte[4];
 435             int         converted;
 436 
 437             try{
 438                 CharBuffer cc = CharBuffer.wrap(convChar);
 439                 ByteBuffer bb = ByteBuffer.allocate(4);
 440                 ISOEncoder.encode(cc, bb, true);
 441                 bb.flip();
 442                 converted = bb.remaining();
 443                 bb.get(convByte,0,converted);
 444             } catch(Exception e) {
 445                 return -1;
 446             }
 447 
 448             if (converted == 2) {
 449                 if (!SODesDefined) {
 450                     newSODesDefined = true;
 451                     ebyte[0] = ISO_ESC;
 452                     tmpByte = SODesig.getBytes();
 453                     System.arraycopy(tmpByte,0,ebyte,1,tmpByte.length);
 454                     index = tmpByte.length+1;
 455                 }
 456                 if (!shiftout) {
 457                     newshiftout = true;
 458                     ebyte[index++] = ISO_SO;
 459                 }
 460                 ebyte[index++] = (byte)(convByte[0] & 0x7f);
 461                 ebyte[index++] = (byte)(convByte[1] & 0x7f);
 462             } else {
 463                 if((convByte[0] == SS2) && (convByte[1] == P2)) {
 464                     if (!SS2DesDefined) {
 465                         newSS2DesDefined = true;
 466                         ebyte[0] = ISO_ESC;
 467                         tmpByte = SS2Desig.getBytes();
 468                         System.arraycopy(tmpByte, 0, ebyte, 1, tmpByte.length);
 469                         index = tmpByte.length+1;
 470                     }
 471                     ebyte[index++] = ISO_ESC;
 472                     ebyte[index++] = ISO_SS2_7;
 473                     ebyte[index++] = (byte)(convByte[2] & 0x7f);
 474                     ebyte[index++] = (byte)(convByte[3] & 0x7f);
 475                 } else if((convByte[0] == SS2)&&(convByte[1] == P3)) {
 476                     if(!SS3DesDefined){
 477                         newSS3DesDefined = true;
 478                         ebyte[0] = ISO_ESC;
 479                         tmpByte = SS3Desig.getBytes();
 480                         System.arraycopy(tmpByte, 0, ebyte, 1, tmpByte.length);
 481                         index = tmpByte.length+1;
 482                     }
 483                     ebyte[index++] = ISO_ESC;
 484                     ebyte[index++] = ISO_SS3_7;
 485                     ebyte[index++] = (byte)(convByte[2] & 0x7f);
 486                     ebyte[index++] = (byte)(convByte[3] & 0x7f);
 487                 }
 488             }
 489             return index;
 490         }
 491 
 492         private CoderResult encodeArrayLoop(CharBuffer src,
 493                                             ByteBuffer dst)
 494         {
 495             char[] sa = src.array();
 496             int sp = src.arrayOffset() + src.position();
 497             int sl = src.arrayOffset() + src.limit();
 498             assert (sp <= sl);
 499             sp = (sp <= sl ? sp : sl);
 500             byte[] da = dst.array();
 501             int dp = dst.arrayOffset() + dst.position();
 502             int dl = dst.arrayOffset() + dst.limit();
 503             assert (dp <= dl);
 504             dp = (dp <= dl ? dp : dl);
 505 
 506             int outputSize = 0;
 507             byte[]  outputByte = new byte[8];
 508             newshiftout = shiftout;
 509             newSODesDefined = SODesDefined;
 510             newSS2DesDefined = SS2DesDefined;
 511             newSS3DesDefined = SS3DesDefined;
 512 
 513             try {
 514                 while (sp < sl) {
 515                     char c = sa[sp];
 516                     if (Surrogate.is(c)) {
 517                         if (sgp.parse(c, sa, sp, sl) < 0)
 518                             return sgp.error();
 519                         return sgp.unmappableResult();
 520                     }
 521 
 522                     if (c < 0x80) {     // ASCII
 523                         if (shiftout){
 524                             newshiftout = false;
 525                             outputSize = 2;
 526                             outputByte[0] = ISO_SI;
 527                             outputByte[1] = (byte)(c & 0x7f);
 528                         } else {
 529                             outputSize = 1;
 530                             outputByte[0] = (byte)(c & 0x7f);
 531                         }
 532                         if(sa[sp] == '\n'){
 533                             newSODesDefined = false;
 534                             newSS2DesDefined = false;
 535                             newSS3DesDefined = false;
 536                         }
 537                     } else {
 538                         outputSize = unicodeToNative(c, outputByte);
 539                         if (outputSize == 0) {
 540                             return CoderResult.unmappableForLength(1);
 541                         }
 542                     }
 543                     if (dl - dp < outputSize)
 544                         return CoderResult.OVERFLOW;
 545 
 546                     for (int i = 0; i < outputSize; i++)
 547                         da[dp++] = outputByte[i];
 548                     sp++;
 549                     shiftout = newshiftout;
 550                     SODesDefined = newSODesDefined;
 551                     SS2DesDefined = newSS2DesDefined;
 552                     SS3DesDefined = newSS3DesDefined;
 553                 }
 554                 return CoderResult.UNDERFLOW;
 555              } finally {
 556                 src.position(sp - src.arrayOffset());
 557                 dst.position(dp - dst.arrayOffset());
 558              }
 559         }
 560 
 561 
 562         private CoderResult encodeBufferLoop(CharBuffer src,
 563                                              ByteBuffer dst)
 564         {
 565             int outputSize = 0;
 566             byte[]  outputByte = new byte[8];
 567             int     inputSize = 0;                 // Size of input
 568             newshiftout = shiftout;
 569             newSODesDefined = SODesDefined;
 570             newSS2DesDefined = SS2DesDefined;
 571             newSS3DesDefined = SS3DesDefined;
 572             int mark = src.position();
 573 
 574             try {
 575                 while (src.hasRemaining()) {
 576                     char inputChar = src.get();
 577                     if (Surrogate.is(inputChar)) {
 578                         if (sgp.parse(inputChar, src) < 0)
 579                             return sgp.error();
 580                         return sgp.unmappableResult();
 581                     }
 582                     if (inputChar < 0x80) {     // ASCII
 583                         if (shiftout){
 584                             newshiftout = false;
 585                             outputSize = 2;
 586                             outputByte[0] = ISO_SI;
 587                             outputByte[1] = (byte)(inputChar & 0x7f);
 588                         } else {
 589                             outputSize = 1;
 590                             outputByte[0] = (byte)(inputChar & 0x7f);
 591                         }
 592                         if(inputChar == '\n'){
 593                             newSODesDefined = false;
 594                             newSS2DesDefined = false;
 595                             newSS3DesDefined = false;
 596                         }
 597                     } else {
 598                         outputSize = unicodeToNative(inputChar, outputByte);
 599                         if (outputSize == 0) {
 600                             return CoderResult.unmappableForLength(1);
 601                         }
 602                     }
 603 
 604                     if (dst.remaining() < outputSize)
 605                         return CoderResult.OVERFLOW;
 606                     for (int i = 0; i < outputSize; i++)
 607                         dst.put(outputByte[i]);
 608                     mark++;
 609                     shiftout = newshiftout;
 610                     SODesDefined = newSODesDefined;
 611                     SS2DesDefined = newSS2DesDefined;
 612                     SS3DesDefined = newSS3DesDefined;
 613                 }
 614                 return CoderResult.UNDERFLOW;
 615             } finally {
 616                 src.position(mark);
 617             }
 618         }
 619 
 620         protected CoderResult encodeLoop(CharBuffer src,
 621                                          ByteBuffer dst)
 622         {
 623             if (src.hasArray() && dst.hasArray())
 624                 return encodeArrayLoop(src, dst);
 625             else
 626                 return encodeBufferLoop(src, dst);
 627         }
 628     }
 629 }