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