1 /*
   2  * Copyright (c) 2001, 2005, 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 package sun.nio.cs.ext;
  27 import java.io.ByteArrayOutputStream;
  28 import java.nio.ByteBuffer;
  29 import java.nio.CharBuffer;
  30 import java.nio.charset.*;
  31 
  32 /**
  33  * An algorithmic conversion from COMPOUND_TEXT to Unicode.
  34  */
  35 
  36 public class COMPOUND_TEXT_Decoder extends CharsetDecoder {
  37 
  38     private static final int NORMAL_BYTES             =  0;
  39     private static final int NONSTANDARD_BYTES        =  1;
  40     private static final int VERSION_SEQUENCE_V       =  2;
  41     private static final int VERSION_SEQUENCE_TERM    =  3;
  42     private static final int ESCAPE_SEQUENCE          =  4;
  43     private static final int CHARSET_NGIIF            =  5;
  44     private static final int CHARSET_NLIIF            =  6;
  45     private static final int CHARSET_NLIF             =  7;
  46     private static final int CHARSET_NRIIF            =  8;
  47     private static final int CHARSET_NRIF             =  9;
  48     private static final int CHARSET_NONSTANDARD_FOML = 10;
  49     private static final int CHARSET_NONSTANDARD_OML  = 11;
  50     private static final int CHARSET_NONSTANDARD_ML   = 12;
  51     private static final int CHARSET_NONSTANDARD_L    = 13;
  52     private static final int CHARSET_NONSTANDARD      = 14;
  53     private static final int CHARSET_LIIF             = 15;
  54     private static final int CHARSET_LIF              = 16;
  55     private static final int CHARSET_RIIF             = 17;
  56     private static final int CHARSET_RIF              = 18;
  57     private static final int CONTROL_SEQUENCE_PIF     = 19;
  58     private static final int CONTROL_SEQUENCE_IF      = 20;
  59     private static final int EXTENSION_ML             = 21;
  60     private static final int EXTENSION_L              = 22;
  61     private static final int EXTENSION                = 23;
  62     private static final int ESCAPE_SEQUENCE_OTHER    = 24;
  63 
  64     private static final String ERR_LATIN1 = "ISO8859_1 unsupported";
  65     private static final String ERR_ILLSTATE = "Illegal state";
  66     private static final String ERR_ESCBYTE =
  67         "Illegal byte in 0x1B escape sequence";
  68     private static final String ERR_ENCODINGBYTE =
  69         "Illegal byte in non-standard character set name";
  70     private static final String ERR_CTRLBYTE =
  71         "Illegal byte in 0x9B control sequence";
  72     private static final String ERR_CTRLPI =
  73         "P following I in 0x9B control sequence";
  74     private static final String ERR_VERSTART =
  75         "Versioning escape sequence can only appear at start of byte stream";
  76     private static final String ERR_VERMANDATORY =
  77         "Cannot parse mandatory extensions";
  78     private static final String ERR_ENCODING = "Unknown encoding: ";
  79     private static final String ERR_FLUSH =
  80         "Escape sequence, control sequence, or ML extension not terminated";
  81 
  82     private int state = NORMAL_BYTES ;
  83     private int ext_count, ext_offset;
  84     private boolean versionSequenceAllowed = true;
  85     private byte[] byteBuf = new byte[1];
  86     private ByteBuffer inBB = ByteBuffer.allocate(16);
  87     private ByteArrayOutputStream queue = new ByteArrayOutputStream(),
  88         encodingQueue = new ByteArrayOutputStream();
  89 
  90     private CharsetDecoder glDecoder, grDecoder, nonStandardDecoder,
  91         lastDecoder;
  92     private boolean glHigh = false, grHigh = true;
  93 
  94 
  95     public COMPOUND_TEXT_Decoder(Charset cs) {
  96         super(cs, 1.0f, 1.0f);
  97         try {
  98             // Initial state in ISO 2022 designates Latin-1 charset.
  99             glDecoder = Charset.forName("ASCII").newDecoder();
 100             grDecoder = Charset.forName("ISO8859_1").newDecoder();
 101         } catch (IllegalArgumentException e) {
 102             error(ERR_LATIN1);
 103         }
 104         initDecoder(glDecoder);
 105         initDecoder(grDecoder);
 106     }
 107 
 108     protected CoderResult decodeLoop(ByteBuffer src, CharBuffer des) {
 109         CoderResult cr = CoderResult.UNDERFLOW;
 110         byte[] input = src.array();
 111         int inOff = src.arrayOffset() + src.position();
 112         int inEnd = src.arrayOffset() + src.limit();
 113 
 114         try {
 115             while (inOff < inEnd && cr.isUnderflow()) {
 116                 // Byte parsing is done with shorts instead of bytes because
 117                 // Java bytes are signed, while COMPOUND_TEXT bytes are not. If
 118                 // we used the Java byte type, the > and < tests during parsing
 119                 // would not work correctly.
 120                 cr = handleByte((short)(input[inOff] & 0xFF), des);
 121                 inOff++;
 122             }
 123             return cr;
 124         } finally {
 125             src.position(inOff - src.arrayOffset());
 126         }
 127     }
 128 
 129     private CoderResult handleByte(short newByte, CharBuffer cb) {
 130         CoderResult cr = CoderResult.UNDERFLOW;
 131         switch (state) {
 132         case NORMAL_BYTES:
 133             cr= normalBytes(newByte, cb);
 134             break;
 135         case NONSTANDARD_BYTES:
 136             cr = nonStandardBytes(newByte, cb);
 137             break;
 138         case VERSION_SEQUENCE_V:
 139         case VERSION_SEQUENCE_TERM:
 140             cr = versionSequence(newByte);
 141             break;
 142         case ESCAPE_SEQUENCE:
 143             cr = escapeSequence(newByte);
 144             break;
 145         case CHARSET_NGIIF:
 146             cr = charset94N(newByte);
 147             break;
 148         case CHARSET_NLIIF:
 149         case CHARSET_NLIF:
 150             cr = charset94NL(newByte, cb);
 151             break;
 152         case CHARSET_NRIIF:
 153         case CHARSET_NRIF:
 154             cr = charset94NR(newByte, cb);
 155             break;
 156         case CHARSET_NONSTANDARD_FOML:
 157         case CHARSET_NONSTANDARD_OML:
 158         case CHARSET_NONSTANDARD_ML:
 159         case CHARSET_NONSTANDARD_L:
 160         case CHARSET_NONSTANDARD:
 161             cr = charsetNonStandard(newByte, cb);
 162             break;
 163         case CHARSET_LIIF:
 164         case CHARSET_LIF:
 165             cr = charset9496L(newByte, cb);
 166             break;
 167         case CHARSET_RIIF:
 168         case CHARSET_RIF:
 169             cr = charset9496R(newByte, cb);
 170             break;
 171         case CONTROL_SEQUENCE_PIF:
 172         case CONTROL_SEQUENCE_IF:
 173             cr = controlSequence(newByte);
 174             break;
 175         case EXTENSION_ML:
 176         case EXTENSION_L:
 177         case EXTENSION:
 178             cr = extension(newByte);
 179             break;
 180         case ESCAPE_SEQUENCE_OTHER:
 181             cr = escapeSequenceOther(newByte);
 182             break;
 183         default:
 184             error(ERR_ILLSTATE);
 185         }
 186         return cr;
 187     }
 188 
 189     private CoderResult normalBytes(short newByte, CharBuffer cb) {
 190         CoderResult cr = CoderResult.UNDERFLOW;
 191         if ((newByte >= 0x00 && newByte <= 0x1F) || // C0
 192             (newByte >= 0x80 && newByte <= 0x9F)) { // C1
 193             char newChar;
 194 
 195             switch (newByte) {
 196             case 0x1B:
 197                 state = ESCAPE_SEQUENCE;
 198                 queue.write(newByte);
 199                 return cr;
 200             case 0x9B:
 201                 state = CONTROL_SEQUENCE_PIF;
 202                 versionSequenceAllowed = false;
 203                 queue.write(newByte);
 204                 return cr;
 205             case 0x09:
 206                 versionSequenceAllowed = false;
 207                 newChar = '\t';
 208                 break;
 209             case 0x0A:
 210                 versionSequenceAllowed = false;
 211                 newChar = '\n';
 212                 break;
 213             default:
 214                 versionSequenceAllowed = false;
 215                 return cr;
 216             }
 217             if (!cb.hasRemaining())
 218                 return CoderResult.OVERFLOW;
 219             else
 220                 cb.put(newChar);
 221         } else {
 222             CharsetDecoder decoder;
 223             boolean high;
 224             versionSequenceAllowed = false;
 225 
 226             if (newByte >= 0x20 && newByte <= 0x7F) {
 227                 decoder = glDecoder;
 228                 high = glHigh;
 229             } else /* if (newByte >= 0xA0 && newByte <= 0xFF) */ {
 230                 decoder = grDecoder;
 231                 high = grHigh;
 232             }
 233             if (lastDecoder != null && decoder != lastDecoder) {
 234                 cr = flushDecoder(lastDecoder, cb);
 235             }
 236             lastDecoder = decoder;
 237 
 238             if (decoder != null) {
 239                 byte b = (byte)newByte;
 240                 if (high) {
 241                     b |= 0x80;
 242                 } else {
 243                     b &= 0x7F;
 244                 }
 245                 inBB.put(b);
 246                 inBB.flip();
 247                 cr = decoder.decode(inBB, cb, false);
 248                 if (!inBB.hasRemaining() || cr.isMalformed()) {
 249                     inBB.clear();
 250                 } else {
 251                   int pos = inBB.limit();
 252                   inBB.clear();
 253                   inBB.position(pos);
 254                 }
 255             } else if (cb.remaining() < replacement().length()) {
 256                 cb.put(replacement());
 257             } else {
 258                 return CoderResult.OVERFLOW;
 259             }
 260         }
 261         return cr;
 262     }
 263 
 264     private CoderResult nonStandardBytes(short newByte, CharBuffer cb)
 265     {
 266         CoderResult cr = CoderResult.UNDERFLOW;
 267         if (nonStandardDecoder != null) {
 268             //byteBuf[0] = (byte)newByte;
 269             inBB.put((byte)newByte);
 270             inBB.flip();
 271             cr = nonStandardDecoder.decode(inBB, cb, false);
 272             if (!inBB.hasRemaining()) {
 273                 inBB.clear();
 274             } else {
 275                 int pos = inBB.limit();
 276                 inBB.clear();
 277                 inBB.position(pos);
 278             }
 279         } else if (cb.remaining() < replacement().length()) {
 280             cb.put(replacement());
 281         } else {
 282             return CoderResult.OVERFLOW;
 283         }
 284 
 285         ext_offset++;
 286         if (ext_offset >= ext_count) {
 287             ext_offset = ext_count = 0;
 288             state = NORMAL_BYTES;
 289             cr = flushDecoder(nonStandardDecoder, cb);
 290             nonStandardDecoder = null;
 291         }
 292         return cr;
 293     }
 294 
 295     private CoderResult escapeSequence(short newByte) {
 296         switch (newByte) {
 297         case 0x23:
 298             state = VERSION_SEQUENCE_V;
 299             break;
 300         case 0x24:
 301             state = CHARSET_NGIIF;
 302             versionSequenceAllowed = false;
 303             break;
 304         case 0x25:
 305             state = CHARSET_NONSTANDARD_FOML;
 306             versionSequenceAllowed = false;
 307             break;
 308         case 0x28:
 309             state = CHARSET_LIIF;
 310             versionSequenceAllowed = false;
 311             break;
 312         case 0x29:
 313         case 0x2D:
 314             state = CHARSET_RIIF;
 315             versionSequenceAllowed = false;
 316             break;
 317         default:
 318             // escapeSequenceOther will write to queue if appropriate
 319             return escapeSequenceOther(newByte);
 320         }
 321 
 322         queue.write(newByte);
 323         return CoderResult.UNDERFLOW;
 324     }
 325 
 326     /**
 327      * Test for unknown, but valid, escape sequences.
 328      */
 329     private CoderResult escapeSequenceOther(short newByte) {
 330         if (newByte >= 0x20 && newByte <= 0x2F) {
 331             // {I}
 332             state = ESCAPE_SEQUENCE_OTHER;
 333             versionSequenceAllowed = false;
 334             queue.write(newByte);
 335         } else if (newByte >= 0x30 && newByte <= 0x7E) {
 336             // F -- end of sequence
 337             state = NORMAL_BYTES;
 338             versionSequenceAllowed = false;
 339             queue.reset();
 340         } else {
 341             return malformedInput(ERR_ESCBYTE);
 342         }
 343         return CoderResult.UNDERFLOW;
 344     }
 345 
 346     /**
 347      * Parses directionality, as well as unknown, but valid, control sequences.
 348      */
 349     private CoderResult controlSequence(short newByte) {
 350         if (newByte >= 0x30 && newByte <= 0x3F) {
 351             // {P}
 352             if (state == CONTROL_SEQUENCE_IF) {
 353                 // P no longer allowed
 354                 return malformedInput(ERR_CTRLPI);
 355             }
 356             queue.write(newByte);
 357         } else if (newByte >= 0x20 && newByte <= 0x2F) {
 358             // {I}
 359             state = CONTROL_SEQUENCE_IF;
 360             queue.write(newByte);
 361         } else if (newByte >= 0x40 && newByte <= 0x7E) {
 362             // F -- end of sequence
 363             state = NORMAL_BYTES;
 364             queue.reset();
 365         } else {
 366             return malformedInput(ERR_CTRLBYTE);
 367         }
 368         return CoderResult.UNDERFLOW;
 369     }
 370 
 371     private CoderResult versionSequence(short newByte) {
 372         if (state == VERSION_SEQUENCE_V) {
 373             if (newByte >= 0x20 && newByte <= 0x2F) {
 374                 state = VERSION_SEQUENCE_TERM;
 375                 queue.write(newByte);
 376             } else {
 377                 return escapeSequenceOther(newByte);
 378             }
 379         } else /* if (state == VERSION_SEQUENCE_TERM) */ {
 380             switch (newByte) {
 381             case 0x30:
 382                 if (!versionSequenceAllowed) {
 383                     return malformedInput(ERR_VERSTART);
 384                 }
 385 
 386                 // OK to ignore extensions
 387                 versionSequenceAllowed = false;
 388                 state = NORMAL_BYTES;
 389                 queue.reset();
 390                 break;
 391             case 0x31:
 392                 return malformedInput((versionSequenceAllowed)
 393                                ? ERR_VERMANDATORY : ERR_VERSTART);
 394             default:
 395                 return escapeSequenceOther(newByte);
 396             }
 397         }
 398         return CoderResult.UNDERFLOW;
 399     }
 400 
 401     private CoderResult charset94N(short newByte) {
 402         switch (newByte) {
 403         case 0x28:
 404             state = CHARSET_NLIIF;
 405             break;
 406         case 0x29:
 407             state = CHARSET_NRIIF;
 408             break;
 409         default:
 410             // escapeSequenceOther will write byte if appropriate
 411             return escapeSequenceOther(newByte);
 412         }
 413 
 414         queue.write(newByte);
 415         return CoderResult.UNDERFLOW;
 416     }
 417 
 418     private CoderResult charset94NL(short newByte, CharBuffer cb) {
 419         if (newByte >= 0x21 &&
 420             newByte <= (state == CHARSET_NLIIF ? 0x23 : 0x2F)) {
 421             // {I}
 422             state = CHARSET_NLIF;
 423             queue.write(newByte);
 424         } else if (newByte >= 0x40 && newByte <= 0x7E) {
 425             // F
 426             return switchDecoder(newByte, cb);
 427         } else {
 428             return escapeSequenceOther(newByte);
 429         }
 430         return CoderResult.UNDERFLOW;
 431     }
 432 
 433     private CoderResult charset94NR(short newByte, CharBuffer cb)
 434     {
 435         if (newByte >= 0x21 &&
 436             newByte <= (state == CHARSET_NRIIF ? 0x23 : 0x2F)) {
 437             // {I}
 438             state = CHARSET_NRIF;
 439             queue.write(newByte);
 440         } else if (newByte >= 0x40 && newByte <= 0x7E) {
 441             // F
 442             return switchDecoder(newByte, cb);
 443         } else {
 444             return escapeSequenceOther(newByte);
 445         }
 446         return CoderResult.UNDERFLOW;
 447     }
 448 
 449     private CoderResult charset9496L(short newByte, CharBuffer cb) {
 450         if (newByte >= 0x21 &&
 451             newByte <= (state == CHARSET_LIIF ? 0x23 : 0x2F)) {
 452             // {I}
 453             state = CHARSET_LIF;
 454             queue.write(newByte);
 455             return CoderResult.UNDERFLOW;
 456         } else if (newByte >= 0x40 && newByte <= 0x7E) {
 457             // F
 458             return switchDecoder(newByte, cb);
 459         } else {
 460             return escapeSequenceOther(newByte);
 461         }
 462     }
 463 
 464     private CoderResult charset9496R(short newByte, CharBuffer cb) {
 465         if (newByte >= 0x21 &&
 466             newByte <= (state == CHARSET_RIIF ? 0x23 : 0x2F)) {
 467             // {I}
 468             state = CHARSET_RIF;
 469             queue.write(newByte);
 470             return CoderResult.UNDERFLOW;
 471         } else if (newByte >= 0x40 && newByte <= 0x7E) {
 472             // F
 473             return switchDecoder(newByte, cb);
 474         } else {
 475             return escapeSequenceOther(newByte);
 476         }
 477     }
 478 
 479     private CoderResult charsetNonStandard(short newByte, CharBuffer cb) {
 480         switch (state) {
 481         case CHARSET_NONSTANDARD_FOML:
 482             if (newByte == 0x2F) {
 483                 state = CHARSET_NONSTANDARD_OML;
 484                 queue.write(newByte);
 485             } else {
 486                 return escapeSequenceOther(newByte);
 487             }
 488             break;
 489         case CHARSET_NONSTANDARD_OML:
 490             if (newByte >= 0x30 && newByte <= 0x34) {
 491                 state = CHARSET_NONSTANDARD_ML;
 492                 queue.write(newByte);
 493             } else if (newByte >= 0x35 && newByte <= 0x3F) {
 494                 state = EXTENSION_ML;
 495                 queue.write(newByte);
 496             } else {
 497                 return escapeSequenceOther(newByte);
 498             }
 499             break;
 500         case CHARSET_NONSTANDARD_ML:
 501             ext_count = (newByte & 0x7F) * 0x80;
 502             state = CHARSET_NONSTANDARD_L;
 503             break;
 504         case CHARSET_NONSTANDARD_L:
 505             ext_count = ext_count + (newByte & 0x7F);
 506             state = (ext_count > 0) ? CHARSET_NONSTANDARD : NORMAL_BYTES;
 507             break;
 508         case CHARSET_NONSTANDARD:
 509             if (newByte == 0x3F || newByte == 0x2A) {
 510                 queue.reset(); // In this case, only current byte is bad.
 511                 return malformedInput(ERR_ENCODINGBYTE);
 512             }
 513             ext_offset++;
 514             if (ext_offset >= ext_count) {
 515                 ext_offset = ext_count = 0;
 516                 state = NORMAL_BYTES;
 517                 queue.reset();
 518                 encodingQueue.reset();
 519             } else if (newByte == 0x02) {
 520                 // encoding name terminator
 521                 return switchDecoder((short)0, cb);
 522             } else {
 523                 encodingQueue.write(newByte);
 524             }
 525             break;
 526         default:
 527             error(ERR_ILLSTATE);
 528         }
 529         return CoderResult.UNDERFLOW;
 530     }
 531 
 532     private CoderResult extension(short newByte) {
 533         switch (state) {
 534         case EXTENSION_ML:
 535             ext_count = (newByte & 0x7F) * 0x80;
 536             state = EXTENSION_L;
 537             break;
 538         case EXTENSION_L:
 539             ext_count = ext_count + (newByte & 0x7F);
 540             state = (ext_count > 0) ? EXTENSION : NORMAL_BYTES;
 541             break;
 542         case EXTENSION:
 543             // Consume 'count' bytes. Don't bother putting them on the queue.
 544             // There may be too many and we can't do anything with them anyway.
 545             ext_offset++;
 546             if (ext_offset >= ext_count) {
 547                 ext_offset = ext_count = 0;
 548                 state = NORMAL_BYTES;
 549                 queue.reset();
 550             }
 551             break;
 552         default:
 553             error(ERR_ILLSTATE);
 554         }
 555         return CoderResult.UNDERFLOW;
 556     }
 557 
 558     /**
 559      * Preconditions:
 560      *   1. 'queue' contains ControlSequence.escSequence
 561      *   2. 'encodingQueue' contains ControlSequence.encoding
 562      */
 563     private CoderResult switchDecoder(short lastByte, CharBuffer cb) {
 564         CoderResult cr = CoderResult.UNDERFLOW;
 565         CharsetDecoder decoder = null;
 566         boolean high = false;
 567         byte[] escSequence;
 568         byte[] encoding = null;
 569 
 570         if (lastByte != 0) {
 571             queue.write(lastByte);
 572         }
 573 
 574         escSequence = queue.toByteArray();
 575         queue.reset();
 576 
 577         if (state == CHARSET_NONSTANDARD) {
 578             encoding = encodingQueue.toByteArray();
 579             encodingQueue.reset();
 580             decoder = CompoundTextSupport.
 581                 getNonStandardDecoder(escSequence, encoding);
 582         } else {
 583             decoder = CompoundTextSupport.getStandardDecoder(escSequence);
 584             high = CompoundTextSupport.getHighBit(escSequence);
 585         }
 586         if (decoder != null) {
 587             initDecoder(decoder);
 588         } else if (unmappableCharacterAction() == CodingErrorAction.REPORT) {
 589             int badInputLength = 1;
 590             if (encoding != null) {
 591                 badInputLength = encoding.length;
 592             } else if (escSequence.length > 0) {
 593                 badInputLength = escSequence.length;
 594             }
 595             return CoderResult.unmappableForLength(badInputLength);
 596         }
 597 
 598         if (state == CHARSET_NLIIF || state == CHARSET_NLIF ||
 599             state == CHARSET_LIIF || state == CHARSET_LIF)
 600         {
 601             if (lastDecoder == glDecoder) {
 602                 cr = flushDecoder(glDecoder, cb);
 603             }
 604             glDecoder = lastDecoder = decoder;
 605             glHigh = high;
 606             state = NORMAL_BYTES;
 607         } else if (state == CHARSET_NRIIF || state == CHARSET_NRIF ||
 608                    state == CHARSET_RIIF || state == CHARSET_RIF) {
 609             if (lastDecoder == grDecoder) {
 610                 cr = flushDecoder(grDecoder, cb);
 611             }
 612             grDecoder = lastDecoder = decoder;
 613             grHigh = high;
 614             state = NORMAL_BYTES;
 615         } else if (state == CHARSET_NONSTANDARD) {
 616             if (lastDecoder != null) {
 617                 cr = flushDecoder(lastDecoder, cb);
 618                 lastDecoder = null;
 619             }
 620             nonStandardDecoder = decoder;
 621             state = NONSTANDARD_BYTES;
 622         } else {
 623             error(ERR_ILLSTATE);
 624         }
 625         return cr;
 626     }
 627 
 628     private ByteBuffer fbb= ByteBuffer.allocate(0);
 629     private CoderResult flushDecoder(CharsetDecoder dec, CharBuffer cb) {
 630         dec.decode(fbb, cb, true);
 631         CoderResult cr = dec.flush(cb);
 632         dec.reset();  //reuse
 633         return cr;
 634     }
 635 
 636     private CoderResult malformedInput(String msg) {
 637         int badInputLength = queue.size() + 1 /* current byte */ ;
 638         queue.reset();
 639         //TBD: nowhere to put the msg in CoderResult
 640         return CoderResult.malformedForLength(badInputLength);
 641     }
 642 
 643     private void error(String msg) {
 644         // For now, throw InternalError. Convert to 'assert' keyword later.
 645         throw new InternalError(msg);
 646     }
 647 
 648     protected CoderResult implFlush(CharBuffer out) {
 649         CoderResult cr = CoderResult.UNDERFLOW;
 650         if (lastDecoder != null)
 651           cr = flushDecoder(lastDecoder, out);
 652         if (state != NORMAL_BYTES)
 653             //TBD message ERR_FLUSH;
 654             cr = CoderResult.malformedForLength(0);
 655         reset();
 656         return cr;
 657     }
 658 
 659     /**
 660      * Resets the decoder.
 661      * Call this method to reset the decoder to its initial state
 662      */
 663     protected void implReset() {
 664         state = NORMAL_BYTES;
 665         ext_count = ext_offset = 0;
 666         versionSequenceAllowed = true;
 667         queue.reset();
 668         encodingQueue.reset();
 669         nonStandardDecoder = lastDecoder = null;
 670         glHigh = false;
 671         grHigh = true;
 672         try {
 673             // Initial state in ISO 2022 designates Latin-1 charset.
 674             glDecoder = Charset.forName("ASCII").newDecoder();
 675             grDecoder = Charset.forName("ISO8859_1").newDecoder();
 676         } catch (IllegalArgumentException e) {
 677             error(ERR_LATIN1);
 678         }
 679         initDecoder(glDecoder);
 680         initDecoder(grDecoder);
 681     }
 682 
 683     protected void implOnMalformedInput(CodingErrorAction newAction) {
 684         if (glDecoder != null)
 685             glDecoder.onMalformedInput(newAction);
 686         if (grDecoder != null)
 687             grDecoder.onMalformedInput(newAction);
 688         if (nonStandardDecoder != null)
 689             nonStandardDecoder.onMalformedInput(newAction);
 690     }
 691 
 692     protected void implOnUnmappableCharacter(CodingErrorAction newAction) {
 693         if (glDecoder != null)
 694             glDecoder.onUnmappableCharacter(newAction);
 695         if (grDecoder != null)
 696             grDecoder.onUnmappableCharacter(newAction);
 697         if (nonStandardDecoder != null)
 698             nonStandardDecoder.onUnmappableCharacter(newAction);
 699     }
 700 
 701     protected void implReplaceWith(String newReplacement) {
 702         if (glDecoder != null)
 703             glDecoder.replaceWith(newReplacement);
 704         if (grDecoder != null)
 705             grDecoder.replaceWith(newReplacement);
 706         if (nonStandardDecoder != null)
 707             nonStandardDecoder.replaceWith(newReplacement);
 708     }
 709 
 710     private void initDecoder(CharsetDecoder dec) {
 711         dec.onUnmappableCharacter(CodingErrorAction.REPLACE)
 712             .replaceWith(replacement());
 713     }
 714 }