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