1 /* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package java.nio.charset; 18 19 import java.nio.BufferOverflowException; 20 import java.nio.BufferUnderflowException; 21 import java.nio.ByteBuffer; 22 import java.nio.CharBuffer; 23 24 /** 25 * A converter that can convert a byte sequence from a charset into a 16-bit 26 * Unicode character sequence. 27 * <p> 28 * The input byte sequence is wrapped by a 29 * {@link java.nio.ByteBuffer ByteBuffer} and the output character sequence is a 30 * {@link java.nio.CharBuffer CharBuffer}. A decoder instance should be used in 31 * the following sequence, which is referred to as a decoding operation: 32 * <ol> 33 * <li>invoking the {@link #reset() reset} method to reset the decoder if the 34 * decoder has been used;</li> 35 * <li>invoking the {@link #decode(ByteBuffer, CharBuffer, boolean) decode} 36 * method until the additional input is not needed, the <code>endOfInput</code> 37 * parameter must be set to false, the input buffer must be filled and the 38 * output buffer must be flushed between invocations;</li> 39 * <li>invoking the {@link #decode(ByteBuffer, CharBuffer, boolean) decode} 40 * method for the last time, and then the <code>endOfInput</code> parameter 41 * must be set to true;</li> 42 * <li>invoking the {@link #flush(CharBuffer) flush} method to flush the 43 * output.</li> 44 * </ol> 45 * <p> 46 * The {@link #decode(ByteBuffer, CharBuffer, boolean) decode} method will 47 * convert as many bytes as possible, and the process won't stop until the input 48 * bytes have run out, the output buffer has been filled or some error has 49 * happened. A {@link CoderResult CoderResult} instance will be returned to 50 * indicate the stop reason, and the invoker can identify the result and choose 51 * further action, which includes filling the input buffer, flushing the output 52 * buffer or recovering from an error and trying again. 53 * <p> 54 * There are two common decoding errors. One is named malformed and it is 55 * returned when the input byte sequence is illegal for the current specific 56 * charset, the other is named unmappable character and it is returned when a 57 * problem occurs mapping a legal input byte sequence to its Unicode character 58 * equivalent. 59 * <p> 60 * Both errors can be handled in three ways, the default one is to report the 61 * error to the invoker by a {@link CoderResult CoderResult} instance, and the 62 * alternatives are to ignore it or to replace the erroneous input with the 63 * replacement string. The replacement string is "\uFFFD" by default and can be 64 * changed by invoking {@link #replaceWith(String) replaceWith} method. The 65 * invoker of this decoder can choose one way by specifying a 66 * {@link CodingErrorAction CodingErrorAction} instance for each error type via 67 * {@link #onMalformedInput(CodingErrorAction) onMalformedInput} method and 68 * {@link #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} 69 * method. 70 * <p> 71 * This is an abstract class and encapsulates many common operations of the 72 * decoding process for all charsets. Decoders for a specific charset should 73 * extend this class and need only to implement the 74 * {@link #decodeLoop(ByteBuffer, CharBuffer) decodeLoop} method for the basic 75 * decoding. If a subclass maintains an internal state, it should override the 76 * {@link #implFlush(CharBuffer) implFlush} method and the 77 * {@link #implReset() implReset} method in addition. 78 * <p> 79 * This class is not thread-safe. 80 * 81 * @see java.nio.charset.Charset 82 * @see java.nio.charset.CharsetEncoder 83 */ 84 public abstract class CharsetDecoder { 85 86 /* 87 * internal status consts 88 */ 89 private static final int INIT = 0; 90 91 private static final int ONGOING = 1; 92 93 private static final int END = 2; 94 95 private static final int FLUSH = 3; 96 97 // average number of chars for one byte 98 private float averChars; 99 100 // maximum number of chars for one byte 101 private float maxChars; 102 103 // charset for this decoder 104 private Charset cs; 105 106 // specify the action if malformed input error encountered 107 private CodingErrorAction malformAction; 108 109 // specify the action if unmappable character error encountered 110 private CodingErrorAction unmapAction; 111 112 // the replacement string 113 private String replace; 114 115 // the current status 116 private int status; 117 118 /** 119 * Constructs a new <code>CharsetDecoder</code> using the given 120 * <code>Charset</code>, average number and maximum number of characters 121 * created by this decoder for one input byte, and the default replacement 122 * string "\uFFFD". 123 * 124 * @param charset 125 * the <code>Charset</code> to be used by this decoder. 126 * @param averageCharsPerByte 127 * the average number of characters created by this decoder for 128 * one input byte, must be positive. 129 * @param maxCharsPerByte 130 * the maximum number of characters created by this decoder for 131 * one input byte, must be positive. 132 * @throws IllegalArgumentException 133 * if <code>averageCharsPerByte</code> or 134 * <code>maxCharsPerByte</code> is negative. 135 */ 136 protected CharsetDecoder(Charset charset, float averageCharsPerByte, 137 float maxCharsPerByte) { 138 if (averageCharsPerByte <= 0 || maxCharsPerByte <= 0) { 139 throw new IllegalArgumentException("averageCharsPerByte and maxCharsPerByte must be positive"); 140 } 141 if (averageCharsPerByte > maxCharsPerByte) { 142 throw new IllegalArgumentException("averageCharsPerByte is greater than maxCharsPerByte"); 143 } 144 averChars = averageCharsPerByte; 145 maxChars = maxCharsPerByte; 146 cs = charset; 147 status = INIT; 148 malformAction = CodingErrorAction.REPORT; 149 unmapAction = CodingErrorAction.REPORT; 150 replace = "\ufffd"; 151 } 152 153 /** 154 * Gets the average number of characters created by this decoder for a 155 * single input byte. 156 * 157 * @return the average number of characters created by this decoder for a 158 * single input byte. 159 */ 160 public final float averageCharsPerByte() { 161 return averChars; 162 } 163 164 /** 165 * Gets the <code>Charset</code> which this decoder uses. 166 * 167 * @return the <code>Charset</code> which this decoder uses. 168 */ 169 public final Charset charset() { 170 return cs; 171 } 172 173 /** 174 * This is a facade method for the decoding operation. 175 * <p> 176 * This method decodes the remaining byte sequence of the given byte buffer 177 * into a new character buffer. This method performs a complete decoding 178 * operation, resets at first, then decodes, and flushes at last. 179 * <p> 180 * This method should not be invoked while another {@code decode} operation 181 * is ongoing. 182 * 183 * @param in 184 * the input buffer. 185 * @return a new <code>CharBuffer</code> containing the the characters 186 * produced by this decoding operation. The buffer's limit will be 187 * the position of the last character in the buffer, and the 188 * position will be zero. 189 * @throws IllegalStateException 190 * if another decoding operation is ongoing. 191 * @throws MalformedInputException 192 * if an illegal input byte sequence for this charset was 193 * encountered, and the action for malformed error is 194 * {@link CodingErrorAction#REPORT CodingErrorAction.REPORT} 195 * @throws UnmappableCharacterException 196 * if a legal but unmappable input byte sequence for this 197 * charset was encountered, and the action for unmappable 198 * character error is 199 * {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}. 200 * Unmappable means the byte sequence at the input buffer's 201 * current position cannot be mapped to a Unicode character 202 * sequence. 203 * @throws CharacterCodingException 204 * if another exception happened during the decode operation. 205 */ 206 public final CharBuffer decode(ByteBuffer in) 207 throws CharacterCodingException { 208 reset(); 209 int length = (int) (in.remaining() * averChars); 210 CharBuffer output = CharBuffer.allocate(length); 211 CoderResult result = null; 212 while (true) { 213 result = decode(in, output, false); 214 checkCoderResult(result); 215 if (result.isUnderflow()) { 216 break; 217 } else if (result.isOverflow()) { 218 output = allocateMore(output); 219 } 220 } 221 result = decode(in, output, true); 222 checkCoderResult(result); 223 224 while (true) { 225 result = flush(output); 226 checkCoderResult(result); 227 if (result.isOverflow()) { 228 output = allocateMore(output); 229 } else { 230 break; 231 } 232 } 233 234 output.flip(); 235 status = FLUSH; 236 return output; 237 } 238 239 /* 240 * checks the result whether it needs to throw CharacterCodingException. 241 */ 242 private void checkCoderResult(CoderResult result) 243 throws CharacterCodingException { 244 if (result.isMalformed() && malformAction == CodingErrorAction.REPORT) { 245 throw new MalformedInputException(result.length()); 246 } else if (result.isUnmappable() 247 && unmapAction == CodingErrorAction.REPORT) { 248 throw new UnmappableCharacterException(result.length()); 249 } 250 } 251 252 /* 253 * original output is full and doesn't have remaining. allocate more space 254 * to new CharBuffer and return it, the contents in the given buffer will be 255 * copied into the new buffer. 256 */ 257 private CharBuffer allocateMore(CharBuffer output) { 258 if (output.capacity() == 0) { 259 return CharBuffer.allocate(1); 260 } 261 CharBuffer result = CharBuffer.allocate(output.capacity() * 2); 262 output.flip(); 263 result.put(output); 264 return result; 265 } 266 267 /** 268 * Decodes bytes starting at the current position of the given input buffer, 269 * and writes the equivalent character sequence into the given output buffer 270 * from its current position. 271 * <p> 272 * The buffers' position will be changed with the reading and writing 273 * operation, but their limits and marks will be kept intact. 274 * <p> 275 * A <code>CoderResult</code> instance will be returned according to 276 * following rules: 277 * <ul> 278 * <li>{@link CoderResult#OVERFLOW CoderResult.OVERFLOW} indicates that 279 * even though not all of the input has been processed, the buffer the 280 * output is being written to has reached its capacity. In the event of this 281 * code being returned this method should be called once more with an 282 * <code>out</code> argument that has not already been filled.</li> 283 * <li>{@link CoderResult#UNDERFLOW CoderResult.UNDERFLOW} indicates that 284 * as many bytes as possible in the input buffer have been decoded. If there 285 * is no further input and no remaining bytes in the input buffer then this 286 * operation may be regarded as complete. Otherwise, this method should be 287 * called once more with additional input.</li> 288 * <li>A {@link CoderResult#malformedForLength(int) malformed input} result 289 * indicates that some malformed input error has been encountered, and the 290 * erroneous bytes start at the input buffer's position and their number can 291 * be got by result's {@link CoderResult#length() length}. This kind of 292 * result can be returned only if the malformed action is 293 * {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}. </li> 294 * <li>A {@link CoderResult#unmappableForLength(int) unmappable character} 295 * result indicates that some unmappable character error has been 296 * encountered, and the erroneous bytes start at the input buffer's position 297 * and their number can be got by result's 298 * {@link CoderResult#length() length}. This kind of result can be returned 299 * only if the unmappable character action is 300 * {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}. </li> 301 * </ul> 302 * <p> 303 * The <code>endOfInput</code> parameter indicates that the invoker cannot 304 * provide further input. This parameter is true if and only if the bytes in 305 * current input buffer are all inputs for this decoding operation. Note 306 * that it is common and won't cause an error if the invoker sets false and 307 * then can't provide more input, while it may cause an error if the invoker 308 * always sets true in several consecutive invocations. This would make the 309 * remaining input to be treated as malformed input. 310 * <p> 311 * This method invokes the 312 * {@link #decodeLoop(ByteBuffer, CharBuffer) decodeLoop} method to 313 * implement the basic decode logic for a specific charset. 314 * 315 * @param in 316 * the input buffer. 317 * @param out 318 * the output buffer. 319 * @param endOfInput 320 * true if all the input characters have been provided. 321 * @return a <code>CoderResult</code> instance which indicates the reason 322 * of termination. 323 * @throws IllegalStateException 324 * if decoding has started or no more input is needed in this 325 * decoding progress. 326 * @throws CoderMalfunctionError 327 * if the {@link #decodeLoop(ByteBuffer, CharBuffer) decodeLoop} 328 * method threw an <code>BufferUnderflowException</code> or 329 * <code>BufferOverflowException</code>. 330 */ 331 public final CoderResult decode(ByteBuffer in, CharBuffer out, 332 boolean endOfInput) { 333 /* 334 * status check 335 */ 336 if ((status == FLUSH) || (!endOfInput && status == END)) { 337 throw new IllegalStateException(); 338 } 339 340 CoderResult result = null; 341 342 // begin to decode 343 while (true) { 344 CodingErrorAction action = null; 345 try { 346 result = decodeLoop(in, out); 347 } catch (BufferOverflowException ex) { 348 // unexpected exception 349 throw new CoderMalfunctionError(ex); 350 } catch (BufferUnderflowException ex) { 351 // unexpected exception 352 throw new CoderMalfunctionError(ex); 353 } 354 355 /* 356 * result handling 357 */ 358 if (result.isUnderflow()) { 359 int remaining = in.remaining(); 360 status = endOfInput ? END : ONGOING; 361 if (endOfInput && remaining > 0) { 362 result = CoderResult.malformedForLength(remaining); 363 } else { 364 return result; 365 } 366 } 367 if (result.isOverflow()) { 368 return result; 369 } 370 // set coding error handle action 371 action = malformAction; 372 if (result.isUnmappable()) { 373 action = unmapAction; 374 } 375 // If the action is IGNORE or REPLACE, we should continue decoding. 376 if (action == CodingErrorAction.REPLACE) { 377 if (out.remaining() < replace.length()) { 378 return CoderResult.OVERFLOW; 379 } 380 out.put(replace); 381 } else { 382 if (action != CodingErrorAction.IGNORE) 383 return result; 384 } 385 in.position(in.position() + result.length()); 386 } 387 } 388 389 /** 390 * Decodes bytes into characters. This method is called by the 391 * {@link #decode(ByteBuffer, CharBuffer, boolean) decode} method. 392 * <p> 393 * This method will implement the essential decoding operation, and it won't 394 * stop decoding until either all the input bytes are read, the output 395 * buffer is filled, or some exception is encountered. Then it will return a 396 * <code>CoderResult</code> object indicating the result of current 397 * decoding operation. The rules to construct the <code>CoderResult</code> 398 * are the same as for 399 * {@link #decode(ByteBuffer, CharBuffer, boolean) decode}. When an 400 * exception is encountered in the decoding operation, most implementations 401 * of this method will return a relevant result object to the 402 * {@link #decode(ByteBuffer, CharBuffer, boolean) decode} method, and some 403 * performance optimized implementation may handle the exception and 404 * implement the error action itself. 405 * <p> 406 * The buffers are scanned from their current positions, and their positions 407 * will be modified accordingly, while their marks and limits will be 408 * intact. At most {@link ByteBuffer#remaining() in.remaining()} characters 409 * will be read, and {@link CharBuffer#remaining() out.remaining()} bytes 410 * will be written. 411 * <p> 412 * Note that some implementations may pre-scan the input buffer and return a 413 * <code>CoderResult.UNDERFLOW</code> until it receives sufficient input. 414 * 415 * @param in 416 * the input buffer. 417 * @param out 418 * the output buffer. 419 * @return a <code>CoderResult</code> instance indicating the result. 420 */ 421 protected abstract CoderResult decodeLoop(ByteBuffer in, CharBuffer out); 422 423 /** 424 * Gets the charset detected by this decoder; this method is optional. 425 * <p> 426 * If implementing an auto-detecting charset, then this decoder returns the 427 * detected charset from this method when it is available. The returned 428 * charset will be the same for the rest of the decode operation. 429 * <p> 430 * If insufficient bytes have been read to determine the charset, an 431 * <code>IllegalStateException</code> will be thrown. 432 * <p> 433 * The default implementation always throws 434 * <code>UnsupportedOperationException</code>, so it should be overridden 435 * by a subclass if needed. 436 * 437 * @return the charset detected by this decoder, or null if it is not yet 438 * determined. 439 * @throws UnsupportedOperationException 440 * if this decoder does not implement an auto-detecting charset. 441 * @throws IllegalStateException 442 * if insufficient bytes have been read to determine the 443 * charset. 444 */ 445 public Charset detectedCharset() { 446 throw new UnsupportedOperationException(); 447 } 448 449 /** 450 * Flushes this decoder. 451 * 452 * This method will call {@link #implFlush(CharBuffer) implFlush}. Some 453 * decoders may need to write some characters to the output buffer when they 454 * have read all input bytes; subclasses can override 455 * {@link #implFlush(CharBuffer) implFlush} to perform the writing operation. 456 * <p> 457 * The maximum number of written bytes won't be larger than 458 * {@link CharBuffer#remaining() out.remaining()}. If some decoder wants to 459 * write more bytes than an output buffer's remaining space allows, then a 460 * <code>CoderResult.OVERFLOW</code> will be returned, and this method 461 * must be called again with a character buffer that has more remaining 462 * space. Otherwise this method will return 463 * <code>CoderResult.UNDERFLOW</code>, which means one decoding process 464 * has been completed successfully. 465 * <p> 466 * During the flush, the output buffer's position will be changed 467 * accordingly, while its mark and limit will be intact. 468 * 469 * @param out 470 * the given output buffer. 471 * @return <code>CoderResult.UNDERFLOW</code> or 472 * <code>CoderResult.OVERFLOW</code>. 473 * @throws IllegalStateException 474 * if this decoder hasn't read all input bytes during one 475 * decoding process, which means neither after calling 476 * {@link #decode(ByteBuffer) decode(ByteBuffer)} nor after 477 * calling {@link #decode(ByteBuffer, CharBuffer, boolean) 478 * decode(ByteBuffer, CharBuffer, boolean)} with true as value 479 * for the last boolean parameter. 480 */ 481 public final CoderResult flush(CharBuffer out) { 482 if (status != END && status != INIT) { 483 throw new IllegalStateException(); 484 } 485 CoderResult result = implFlush(out); 486 if (result == CoderResult.UNDERFLOW) { 487 status = FLUSH; 488 } 489 return result; 490 } 491 492 /** 493 * Flushes this decoder. The default implementation does nothing and always 494 * returns <code>CoderResult.UNDERFLOW</code>; this method can be 495 * overridden if needed. 496 * 497 * @param out 498 * the output buffer. 499 * @return <code>CoderResult.UNDERFLOW</code> or 500 * <code>CoderResult.OVERFLOW</code>. 501 */ 502 protected CoderResult implFlush(CharBuffer out) { 503 return CoderResult.UNDERFLOW; 504 } 505 506 /** 507 * Notifies that this decoder's <code>CodingErrorAction</code> specified 508 * for malformed input error has been changed. The default implementation 509 * does nothing; this method can be overridden if needed. 510 * 511 * @param newAction 512 * the new action. 513 */ 514 protected void implOnMalformedInput(CodingErrorAction newAction) { 515 // default implementation is empty 516 } 517 518 /** 519 * Notifies that this decoder's <code>CodingErrorAction</code> specified 520 * for unmappable character error has been changed. The default 521 * implementation does nothing; this method can be overridden if needed. 522 * 523 * @param newAction 524 * the new action. 525 */ 526 protected void implOnUnmappableCharacter(CodingErrorAction newAction) { 527 // default implementation is empty 528 } 529 530 /** 531 * Notifies that this decoder's replacement has been changed. The default 532 * implementation does nothing; this method can be overridden if needed. 533 * 534 * @param newReplacement 535 * the new replacement string. 536 */ 537 protected void implReplaceWith(String newReplacement) { 538 // default implementation is empty 539 } 540 541 /** 542 * Reset this decoder's charset related state. The default implementation 543 * does nothing; this method can be overridden if needed. 544 */ 545 protected void implReset() { 546 // default implementation is empty 547 } 548 549 /** 550 * Indicates whether this decoder implements an auto-detecting charset. 551 * 552 * @return <code>true</code> if this decoder implements an auto-detecting 553 * charset. 554 */ 555 public boolean isAutoDetecting() { 556 return false; 557 } 558 559 /** 560 * Indicates whether this decoder has detected a charset; this method is 561 * optional. 562 * <p> 563 * If this decoder implements an auto-detecting charset, then this method 564 * may start to return true during decoding operation to indicate that a 565 * charset has been detected in the input bytes and that the charset can be 566 * retrieved by invoking the {@link #detectedCharset() detectedCharset} 567 * method. 568 * <p> 569 * Note that a decoder that implements an auto-detecting charset may still 570 * succeed in decoding a portion of the given input even when it is unable 571 * to detect the charset. For this reason users should be aware that a 572 * <code>false</code> return value does not indicate that no decoding took 573 * place. 574 * <p> 575 * The default implementation always throws an 576 * <code>UnsupportedOperationException</code>; it should be overridden by 577 * a subclass if needed. 578 * 579 * @return <code>true</code> if this decoder has detected a charset. 580 * @throws UnsupportedOperationException 581 * if this decoder doesn't implement an auto-detecting charset. 582 */ 583 public boolean isCharsetDetected() { 584 throw new UnsupportedOperationException(); 585 } 586 587 /** 588 * Gets this decoder's <code>CodingErrorAction</code> when malformed input 589 * occurred during the decoding process. 590 * 591 * @return this decoder's <code>CodingErrorAction</code> when malformed 592 * input occurred during the decoding process. 593 */ 594 public CodingErrorAction malformedInputAction() { 595 return malformAction; 596 } 597 598 /** 599 * Gets the maximum number of characters which can be created by this 600 * decoder for one input byte, must be positive. 601 * 602 * @return the maximum number of characters which can be created by this 603 * decoder for one input byte, must be positive. 604 */ 605 public final float maxCharsPerByte() { 606 return maxChars; 607 } 608 609 /** 610 * Sets this decoder's action on malformed input errors. 611 * 612 * This method will call the 613 * {@link #implOnMalformedInput(CodingErrorAction) implOnMalformedInput} 614 * method with the given new action as argument. 615 * 616 * @param newAction 617 * the new action on malformed input error. 618 * @return this decoder. 619 * @throws IllegalArgumentException 620 * if {@code newAction} is {@code null}. 621 */ 622 public final CharsetDecoder onMalformedInput(CodingErrorAction newAction) { 623 if (null == newAction) { 624 throw new IllegalArgumentException(); 625 } 626 malformAction = newAction; 627 implOnMalformedInput(newAction); 628 return this; 629 } 630 631 /** 632 * Sets this decoder's action on unmappable character errors. 633 * 634 * This method will call the 635 * {@link #implOnUnmappableCharacter(CodingErrorAction) implOnUnmappableCharacter} 636 * method with the given new action as argument. 637 * 638 * @param newAction 639 * the new action on unmappable character error. 640 * @return this decoder. 641 * @throws IllegalArgumentException 642 * if {@code newAction} is {@code null}. 643 */ 644 public final CharsetDecoder onUnmappableCharacter( 645 CodingErrorAction newAction) { 646 if (null == newAction) { 647 throw new IllegalArgumentException(); 648 } 649 unmapAction = newAction; 650 implOnUnmappableCharacter(newAction); 651 return this; 652 } 653 654 /** 655 * Gets the replacement string, which is never null or empty. 656 * 657 * @return the replacement string, cannot be null or empty. 658 */ 659 public final String replacement() { 660 return replace; 661 } 662 663 /** 664 * Sets the new replacement string. 665 * 666 * This method first checks the given replacement's validity, then changes 667 * the replacement value, and at last calls the 668 * {@link #implReplaceWith(String) implReplaceWith} method with the given 669 * new replacement as argument. 670 * 671 * @param newReplacement 672 * the replacement string, cannot be null or empty. Its length 673 * cannot be larger than {@link #maxCharsPerByte()}. 674 * @return this decoder. 675 * @throws IllegalArgumentException 676 * if the given replacement cannot satisfy the requirement 677 * mentioned above. 678 */ 679 public final CharsetDecoder replaceWith(String newReplacement) { 680 if (newReplacement == null || newReplacement.isEmpty()) { 681 throw new IllegalArgumentException("Replacement string cannot be null or empty"); 682 } 683 if (newReplacement.length() > maxChars) { 684 throw new IllegalArgumentException("Replacement string cannot be longer than max characters per byte"); 685 } 686 replace = newReplacement; 687 implReplaceWith(newReplacement); 688 return this; 689 } 690 691 /** 692 * Resets this decoder. This method will reset the internal status, and then 693 * calls <code>implReset()</code> to reset any status related to the 694 * specific charset. 695 * 696 * @return this decoder. 697 */ 698 public final CharsetDecoder reset() { 699 status = INIT; 700 implReset(); 701 return this; 702 } 703 704 /** 705 * Gets this decoder's <code>CodingErrorAction</code> when an unmappable 706 * character error occurred during the decoding process. 707 * 708 * @return this decoder's <code>CodingErrorAction</code> when an 709 * unmappable character error occurred during the decoding process. 710 */ 711 public CodingErrorAction unmappableCharacterAction() { 712 return unmapAction; 713 } 714 } 715