1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/* Licensed to the Apache Software Foundation (ASF) under one or more
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements.  See the NOTICE file distributed with
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership.
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License.  You may obtain a copy of the License at
7f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
9f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License.
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.nio.charset;
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.BufferOverflowException;
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.BufferUnderflowException;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.ByteBuffer;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.CharBuffer;
238454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughesimport java.util.Arrays;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
2657a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * Transforms a sequence of 16-bit Java characters to a byte sequence in some encoding.
2757a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes *
2857a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>The input character sequence is a {@link java.nio.CharBuffer CharBuffer} and the
2957a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * output byte sequence is a {@link java.nio.ByteBuffer ByteBuffer}.
3057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes *
3157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>Use {@link #encode(CharBuffer)} to encode an entire {@code CharBuffer} to a
3257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * new {@code ByteBuffer}, or {@link #encode(CharBuffer, ByteBuffer, boolean)} for more
3357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * control. When using the latter method, the entire operation proceeds as follows:
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <ol>
3557a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <li>Invoke {@link #reset()} to reset the encoder if this instance has been used before.</li>
3657a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <li>Invoke {@link #encode(CharBuffer, ByteBuffer, boolean) encode} with the {@code endOfInput}
3757a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * parameter set to false until additional input is not needed (as signaled by the return value).
3857a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * The input buffer must be filled and the output buffer must be flushed between invocations.
3957a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>The {@link #encode(CharBuffer, ByteBuffer, boolean) encode} method will
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * convert as many characters as possible, and the process won't stop until the
4157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * input buffer has been exhausted, the output buffer has been filled, or an
4257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * error has occurred. A {@link CoderResult CoderResult} instance will be
4357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * returned to indicate the current state. The caller should fill the input buffer, flush
4457a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * the output buffer, or recovering from an error and try again, accordingly.
4557a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * </li>
4657a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <li>Invoke {@link #encode(CharBuffer, ByteBuffer, boolean) encode} for the last time with
4757a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * {@code endOfInput} set to true.</li>
4857a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <li>Invoke {@link #flush(ByteBuffer)} to flush remaining output.</li>
4957a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * </ol>
5057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes *
5157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>There are two classes of encoding error: <i>malformed input</i>
5257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * signifies that the input character sequence is not legal, while <i>unmappable character</i>
5357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * signifies that the input is legal but cannot be mapped to a byte sequence (because the charset
5457a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * cannot represent the character, for example).
5557a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes *
5657a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>Errors can be handled in three ways. The default is to
57b10f4611e8c74fd4e996c8ed999a16d81f0df986Elliott Hughes * {@link CodingErrorAction#REPORT report} the error to the caller. The alternatives are to
58b10f4611e8c74fd4e996c8ed999a16d81f0df986Elliott Hughes * {@link CodingErrorAction#IGNORE ignore} the error or {@link CodingErrorAction#REPLACE replace}
5957a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * the problematic input with the byte sequence returned by {@link #replacement}. The disposition
6057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * for each of the two kinds of error can be set independently using the {@link #onMalformedInput}
6157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * and {@link #onUnmappableCharacter} methods.
6257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes *
6357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>The default replacement bytes depend on the charset but can be overridden using the
6457a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * {@link #replaceWith} method.
6557a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes *
6657a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>This class is abstract and encapsulates many common operations of the
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * encoding process for all charsets. Encoders for a specific charset should
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * extend this class and need only to implement the
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@link #encodeLoop(CharBuffer, ByteBuffer) encodeLoop} method for basic
7057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * encoding. If a subclass maintains internal state, it should also override the
7157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * {@link #implFlush(ByteBuffer) implFlush} and {@link #implReset() implReset} methods.
7257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes *
7357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>This class is not thread-safe.
74eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson *
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see java.nio.charset.Charset
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see java.nio.charset.CharsetDecoder
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic abstract class CharsetEncoder {
790f702e293cb57da788261a80abc84391543f6791Elliott Hughes    private static final String RESET = "RESET";
800f702e293cb57da788261a80abc84391543f6791Elliott Hughes    private static final String ONGOING = "ONGOING";
810f702e293cb57da788261a80abc84391543f6791Elliott Hughes    private static final String END_OF_INPUT = "END_OF_INPUT";
820f702e293cb57da788261a80abc84391543f6791Elliott Hughes    private static final String FLUSHED = "FLUSHED";
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
840f702e293cb57da788261a80abc84391543f6791Elliott Hughes    private final Charset charset;
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes    private final float averageBytesPerChar;
8737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes    private final float maxBytesPerChar;
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8937871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes    private byte[] replacementBytes;
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
910f702e293cb57da788261a80abc84391543f6791Elliott Hughes    private String state = RESET;
9230a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes
930f702e293cb57da788261a80abc84391543f6791Elliott Hughes    private CodingErrorAction malformedInputAction = CodingErrorAction.REPORT;
940f702e293cb57da788261a80abc84391543f6791Elliott Hughes    private CodingErrorAction unmappableCharacterAction = CodingErrorAction.REPORT;
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes    // decoder instance for this encoder's charset, used for replacement value checking
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private CharsetDecoder decoder;
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
100c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes     * Constructs a new {@code CharsetEncoder} using the given parameters and
101c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes     * the replacement byte array {@code { (byte) '?' }}.
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
103cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes    protected CharsetEncoder(Charset cs, float averageBytesPerChar, float maxBytesPerChar) {
104cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes        this(cs, averageBytesPerChar, maxBytesPerChar, new byte[] { (byte) '?' });
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new <code>CharsetEncoder</code> using the given
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>Charset</code>, replacement byte array, average number and
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * maximum number of bytes created by this encoder for one input character.
111f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param cs
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the <code>Charset</code> to be used by this encoder.
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param averageBytesPerChar
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            average number of bytes created by this encoder for one single
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            input character, must be positive.
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param maxBytesPerChar
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            maximum number of bytes which can be created by this encoder
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            for one single input character, must be positive.
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param replacement
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the replacement byte array, cannot be null or empty, its
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            length cannot be larger than <code>maxBytesPerChar</code>,
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            and must be a legal replacement, which can be justified by
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            {@link #isLegalReplacement(byte[]) isLegalReplacement}.
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if any parameters are invalid.
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1283664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes    protected CharsetEncoder(Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement) {
1293664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes        this(cs, averageBytesPerChar, maxBytesPerChar, replacement, false);
1303664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes    }
1313664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes
1323664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes    CharsetEncoder(Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement, boolean trusted) {
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (averageBytesPerChar <= 0 || maxBytesPerChar <= 0) {
1348454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalArgumentException("averageBytesPerChar and maxBytesPerChar must both be positive");
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (averageBytesPerChar > maxBytesPerChar) {
1378454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalArgumentException("averageBytesPerChar is greater than maxBytesPerChar");
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1390f702e293cb57da788261a80abc84391543f6791Elliott Hughes        this.charset = cs;
14037871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        this.averageBytesPerChar = averageBytesPerChar;
14137871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        this.maxBytesPerChar = maxBytesPerChar;
1423664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes        if (trusted) {
1433664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes            // The RI enforces unnecessary restrictions on the replacement bytes. We trust ICU to
1443664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes            // know what it's doing. Doing so lets us support ICU's EUC-JP, SCSU, and Shift_JIS.
1453664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes            this.replacementBytes = replacement;
1463664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes        } else {
1473664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes            replaceWith(replacement);
1483664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes        }
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
15237871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes     * Returns the average number of bytes created by this encoder for a single
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * input character.
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final float averageBytesPerChar() {
15637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        return averageBytesPerChar;
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1605ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes     * Tests whether the given character can be encoded by this encoder.
1615ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes     *
1620f702e293cb57da788261a80abc84391543f6791Elliott Hughes     * <p>Note that this method may change the internal state of this encoder, so
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * it should not be called when another encoding process is ongoing,
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * otherwise it will throw an <code>IllegalStateException</code>.
165eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
1665ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes     * @throws IllegalStateException if another encode process is ongoing.
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean canEncode(char c) {
1695ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        return canEncode(CharBuffer.wrap(new char[] { c }));
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1735ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes     * Tests whether the given <code>CharSequence</code> can be encoded by this
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * encoder.
175f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
1760f702e293cb57da788261a80abc84391543f6791Elliott Hughes     * <p>Note that this method may change the internal state of this encoder, so
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * it should not be called when another encode process is ongoing, otherwise
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * it will throw an <code>IllegalStateException</code>.
179f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
1805ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes     * @throws IllegalStateException if another encode process is ongoing.
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean canEncode(CharSequence sequence) {
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CharBuffer cb;
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (sequence instanceof CharBuffer) {
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            cb = ((CharBuffer) sequence).duplicate();
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            cb = CharBuffer.wrap(sequence);
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1895ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes
1900f702e293cb57da788261a80abc84391543f6791Elliott Hughes        if (state == FLUSHED) {
1910f702e293cb57da788261a80abc84391543f6791Elliott Hughes            reset();
1925ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        }
1930f702e293cb57da788261a80abc84391543f6791Elliott Hughes        if (state != RESET) {
1940f702e293cb57da788261a80abc84391543f6791Elliott Hughes            throw illegalStateException();
1955ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        }
1960f702e293cb57da788261a80abc84391543f6791Elliott Hughes
1975ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        CodingErrorAction originalMalformedInputAction = malformedInputAction;
1985ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        CodingErrorAction originalUnmappableCharacterAction = unmappableCharacterAction;
1995ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        onMalformedInput(CodingErrorAction.REPORT);
2005ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        onUnmappableCharacter(CodingErrorAction.REPORT);
2015ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        try {
2029edca89080204647492b04f848107bcb90798a1cElliott Hughes            encode(cb);
2035ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes            return true;
2045ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        } catch (CharacterCodingException e) {
2055ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes            return false;
2065ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        } finally {
2075ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes            onMalformedInput(originalMalformedInputAction);
2085ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes            onUnmappableCharacter(originalUnmappableCharacterAction);
2095ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes            reset();
2105ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        }
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
21437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes     * Returns the {@link Charset} which this encoder uses.
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final Charset charset() {
2170f702e293cb57da788261a80abc84391543f6791Elliott Hughes        return charset;
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This is a facade method for the encoding operation.
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method encodes the remaining character sequence of the given
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * character buffer into a new byte buffer. This method performs a complete
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * encoding operation, resets at first, then encodes, and flushes at last.
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method should not be invoked if another encode operation is ongoing.
228eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the input buffer.
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a new <code>ByteBuffer</code> containing the bytes produced by
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         this encoding operation. The buffer's limit will be the position
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         of the last byte in the buffer, and the position will be zero.
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalStateException
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if another encoding operation is ongoing.
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws MalformedInputException
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an illegal input character sequence for this charset is
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             encountered, and the action for malformed error is
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws UnmappableCharacterException
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if a legal but unmappable input character sequence for this
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             charset is encountered, and the action for unmappable
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             character error is
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}.
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             Unmappable means the Unicode character sequence at the input
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             buffer's current position cannot be mapped to a equivalent
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             byte sequence.
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws CharacterCodingException
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if other exception happened during the encode operation.
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
25157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes    public final ByteBuffer encode(CharBuffer in) throws CharacterCodingException {
2525ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        int length = (int) (in.remaining() * averageBytesPerChar);
2535ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        ByteBuffer out = ByteBuffer.allocate(length);
2545ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        reset();
2565ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes
2570f702e293cb57da788261a80abc84391543f6791Elliott Hughes        while (state != FLUSHED) {
2585ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes            CoderResult result = encode(in, out, true);
2590f702e293cb57da788261a80abc84391543f6791Elliott Hughes            if (result == CoderResult.OVERFLOW) {
2605ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes                out = allocateMore(out);
2610f702e293cb57da788261a80abc84391543f6791Elliott Hughes                continue; // No point trying to flush to an already-full buffer.
2625ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes            } else {
2635ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes                checkCoderResult(result);
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2665ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes            result = flush(out);
2670f702e293cb57da788261a80abc84391543f6791Elliott Hughes            if (result == CoderResult.OVERFLOW) {
2685ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes                out = allocateMore(out);
2695ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes            } else {
2705ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes                checkCoderResult(result);
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
2735ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes
2745ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        out.flip();
2755ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        return out;
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
27857a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes    private void checkCoderResult(CoderResult result) throws CharacterCodingException {
2795ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes        if (malformedInputAction == CodingErrorAction.REPORT && result.isMalformed()) {
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new MalformedInputException(result.length());
28137871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        } else if (unmappableCharacterAction == CodingErrorAction.REPORT && result.isUnmappable()) {
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new UnmappableCharacterException(result.length());
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private ByteBuffer allocateMore(ByteBuffer output) {
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (output.capacity() == 0) {
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return ByteBuffer.allocate(1);
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ByteBuffer result = ByteBuffer.allocate(output.capacity() * 2);
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        output.flip();
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        result.put(output);
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Encodes characters starting at the current position of the given input
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * buffer, and writes the equivalent byte sequence into the given output
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * buffer from its current position.
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The buffers' position will be changed with the reading and writing
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * operation, but their limits and marks will be kept intact.
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * A <code>CoderResult</code> instance will be returned according to
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * following rules:
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <ul>
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>A {@link CoderResult#malformedForLength(int) malformed input} result
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * indicates that some malformed input error was encountered, and the
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * erroneous characters start at the input buffer's position and their
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * number can be got by result's {@link CoderResult#length() length}. This
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * kind of result can be returned only if the malformed action is
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}.</li>
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>{@link CoderResult#UNDERFLOW CoderResult.UNDERFLOW} indicates that
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * as many characters as possible in the input buffer have been encoded. If
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * there is no further input and no characters left in the input buffer then
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * this task is complete. If this is not the case then the client should
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * call this method again supplying some more input characters.</li>
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>{@link CoderResult#OVERFLOW CoderResult.OVERFLOW} indicates that the
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * output buffer has been filled, while there are still some characters
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * remaining in the input buffer. This method should be invoked again with a
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * non-full output buffer.</li>
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>A {@link CoderResult#unmappableForLength(int) unmappable character}
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * result indicates that some unmappable character error was encountered,
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * and the erroneous characters start at the input buffer's position and
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * their number can be got by result's {@link CoderResult#length() length}.
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This kind of result can be returned only on
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}.</li>
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * </ul>
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The <code>endOfInput</code> parameter indicates if the invoker can
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * provider further input. This parameter is true if and only if the
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * characters in the current input buffer are all inputs for this encoding
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * operation. Note that it is common and won't cause an error if the invoker
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * sets false and then has no more input available, while it may cause an
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * error if the invoker always sets true in several consecutive invocations.
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This would make the remaining input to be treated as malformed input.
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * input.
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method invokes the
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #encodeLoop(CharBuffer, ByteBuffer) encodeLoop} method to
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * implement the basic encode logic for a specific charset.
342eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the input buffer.
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the output buffer.
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param endOfInput
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            true if all the input characters have been provided.
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a <code>CoderResult</code> instance indicating the result.
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalStateException
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the encoding operation has already started or no more
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             input is needed in this encoding process.
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws CoderMalfunctionError
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             If the {@link #encodeLoop(CharBuffer, ByteBuffer) encodeLoop}
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             method threw an <code>BufferUnderflowException</code> or
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             <code>BufferUnderflowException</code>.
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
358cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes    public final CoderResult encode(CharBuffer in, ByteBuffer out, boolean endOfInput) {
3590f702e293cb57da788261a80abc84391543f6791Elliott Hughes        if (state != RESET && state != ONGOING && !(endOfInput && state == END_OF_INPUT)) {
3600f702e293cb57da788261a80abc84391543f6791Elliott Hughes            throw illegalStateException();
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
3630f702e293cb57da788261a80abc84391543f6791Elliott Hughes        state = endOfInput ? END_OF_INPUT : ONGOING;
3645ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (true) {
3665ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes            CoderResult result;
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                result = encodeLoop(in, out);
3690f702e293cb57da788261a80abc84391543f6791Elliott Hughes            } catch (BufferOverflowException ex) {
3700f702e293cb57da788261a80abc84391543f6791Elliott Hughes                throw new CoderMalfunctionError(ex);
3710f702e293cb57da788261a80abc84391543f6791Elliott Hughes            } catch (BufferUnderflowException ex) {
3720f702e293cb57da788261a80abc84391543f6791Elliott Hughes                throw new CoderMalfunctionError(ex);
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
3740f702e293cb57da788261a80abc84391543f6791Elliott Hughes
3755ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes            if (result == CoderResult.UNDERFLOW) {
3765ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes                if (endOfInput && in.hasRemaining()) {
3775ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes                    result = CoderResult.malformedForLength(in.remaining());
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return result;
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
3815ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes            } else if (result == CoderResult.OVERFLOW) {
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return result;
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
3840f702e293cb57da788261a80abc84391543f6791Elliott Hughes
3850f702e293cb57da788261a80abc84391543f6791Elliott Hughes            // We have a real error, so do what the appropriate action tells us what to do...
3865ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes            CodingErrorAction action =
3875ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes                    result.isUnmappable() ? unmappableCharacterAction : malformedInputAction;
3885ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes            if (action == CodingErrorAction.REPORT) {
3895ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes                return result;
3900f702e293cb57da788261a80abc84391543f6791Elliott Hughes            } else if (action == CodingErrorAction.REPLACE) {
39137871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes                if (out.remaining() < replacementBytes.length) {
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return CoderResult.OVERFLOW;
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
39437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes                out.put(replacementBytes);
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            in.position(in.position() + result.length());
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Encodes characters into bytes. This method is called by
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #encode(CharBuffer, ByteBuffer, boolean) encode}.
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method will implement the essential encoding operation, and it won't
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * stop encoding until either all the input characters are read, the output
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * buffer is filled, or some exception is encountered. Then it will
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * return a <code>CoderResult</code> object indicating the result of the
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * current encoding operation. The rule to construct the
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>CoderResult</code> is the same as for
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #encode(CharBuffer, ByteBuffer, boolean) encode}. When an
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * exception is encountered in the encoding operation, most implementations
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * of this method will return a relevant result object to the
4135ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes     * {@link #encode(CharBuffer, ByteBuffer, boolean) encode} method, and
4145ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes     * subclasses may handle the exception and
4155ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes     * implement the error action themselves.
416eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * <p>
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The buffers are scanned from their current positions, and their positions
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * will be modified accordingly, while their marks and limits will be
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * intact. At most {@link CharBuffer#remaining() in.remaining()} characters
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * will be read, and {@link ByteBuffer#remaining() out.remaining()} bytes
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * will be written.
422eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * <p>
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Note that some implementations may pre-scan the input buffer and return
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>CoderResult.UNDERFLOW</code> until it receives sufficient input.
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the input buffer.
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the output buffer.
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a <code>CoderResult</code> instance indicating the result.
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected abstract CoderResult encodeLoop(CharBuffer in, ByteBuffer out);
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Flushes this encoder.
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method will call {@link #implFlush(ByteBuffer) implFlush}. Some
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * encoders may need to write some bytes to the output buffer when they have
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * read all input characters, subclasses can overridden
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #implFlush(ByteBuffer) implFlush} to perform writing action.
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The maximum number of written bytes won't larger than
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link ByteBuffer#remaining() out.remaining()}. If some encoder wants to
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * write more bytes than the output buffer's available remaining space, then
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>CoderResult.OVERFLOW</code> will be returned, and this method
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * must be called again with a byte buffer that has free space. Otherwise
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * this method will return <code>CoderResult.UNDERFLOW</code>, which
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * means one encoding process has been completed successfully.
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * During the flush, the output buffer's position will be changed
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * accordingly, while its mark and limit will be intact.
452f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given output buffer.
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return <code>CoderResult.UNDERFLOW</code> or
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         <code>CoderResult.OVERFLOW</code>.
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalStateException
4580f702e293cb57da788261a80abc84391543f6791Elliott Hughes     *             if this encoder isn't already flushed or at end of input.
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final CoderResult flush(ByteBuffer out) {
4610f702e293cb57da788261a80abc84391543f6791Elliott Hughes        if (state != FLUSHED && state != END_OF_INPUT) {
4620f702e293cb57da788261a80abc84391543f6791Elliott Hughes            throw illegalStateException();
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CoderResult result = implFlush(out);
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (result == CoderResult.UNDERFLOW) {
4660f702e293cb57da788261a80abc84391543f6791Elliott Hughes            state = FLUSHED;
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Flushes this encoder. The default implementation does nothing and always
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * returns <code>CoderResult.UNDERFLOW</code>; this method can be
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * overridden if needed.
475f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the output buffer.
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return <code>CoderResult.UNDERFLOW</code> or
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         <code>CoderResult.OVERFLOW</code>.
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected CoderResult implFlush(ByteBuffer out) {
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return CoderResult.UNDERFLOW;
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Notifies that this encoder's <code>CodingErrorAction</code> specified
487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for malformed input error has been changed. The default implementation
488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * does nothing; this method can be overridden if needed.
489f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param newAction
491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new action.
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void implOnMalformedInput(CodingErrorAction newAction) {
494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // default implementation is empty
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Notifies that this encoder's <code>CodingErrorAction</code> specified
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for unmappable character error has been changed. The default
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * implementation does nothing; this method can be overridden if needed.
501f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
502adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param newAction
503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new action.
504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void implOnUnmappableCharacter(CodingErrorAction newAction) {
506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // default implementation is empty
507adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
508adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Notifies that this encoder's replacement has been changed. The default
511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * implementation does nothing; this method can be overridden if needed.
512f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param newReplacement
514adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new replacement string.
515adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
516adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void implReplaceWith(byte[] newReplacement) {
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // default implementation is empty
518adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
520adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Resets this encoder's charset related state. The default implementation
522adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * does nothing; this method can be overridden if needed.
523adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
524adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void implReset() {
525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // default implementation is empty
526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
528adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
5295ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes     * Tests whether the given argument is legal as this encoder's replacement byte
5305ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes     * array. The given byte array is legal if and only if it can be decoded into
5315ec6bf8d033754e06a463adb091d2c0afd0755acElliott Hughes     * characters.
532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
53357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes    public boolean isLegalReplacement(byte[] replacement) {
534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (decoder == null) {
5350f702e293cb57da788261a80abc84391543f6791Elliott Hughes            decoder = charset.newDecoder();
53657a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes            decoder.onMalformedInput(CodingErrorAction.REPORT);
53757a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes            decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
538adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
53957a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        ByteBuffer in = ByteBuffer.wrap(replacement);
54057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        CharBuffer out = CharBuffer.allocate((int) (replacement.length * decoder.maxCharsPerByte()));
541adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CoderResult result = decoder.decode(in, out, true);
542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return !result.isError();
543adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
545adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
54637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes     * Returns this encoder's <code>CodingErrorAction</code> when a malformed
547adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * input error occurred during the encoding process.
548adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
549adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public CodingErrorAction malformedInputAction() {
55037871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        return malformedInputAction;
551adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
552adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
55437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes     * Returns the maximum number of bytes which can be created by this encoder for
555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * one input character, must be positive.
556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final float maxBytesPerChar() {
55837871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        return maxBytesPerChar;
559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
560adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
562adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets this encoder's action on malformed input error.
563f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method will call the
565adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #implOnMalformedInput(CodingErrorAction) implOnMalformedInput}
566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * method with the given new action as argument.
567f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param newAction
569adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new action on malformed input error.
570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this encoder.
571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
572adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the given newAction is null.
573adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
574adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final CharsetEncoder onMalformedInput(CodingErrorAction newAction) {
5758454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes        if (newAction == null) {
5768454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalArgumentException("newAction == null");
577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
57837871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        malformedInputAction = newAction;
579adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        implOnMalformedInput(newAction);
580adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this;
581adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
582adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
584adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets this encoder's action on unmappable character error.
585f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
586adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method will call the
587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #implOnUnmappableCharacter(CodingErrorAction) implOnUnmappableCharacter}
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * method with the given new action as argument.
589f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
590adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param newAction
591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new action on unmappable character error.
592adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this encoder.
593adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
594adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the given newAction is null.
595adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
5968454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes    public final CharsetEncoder onUnmappableCharacter(CodingErrorAction newAction) {
5978454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes        if (newAction == null) {
5988454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalArgumentException("newAction == null");
599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
60037871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        unmappableCharacterAction = newAction;
601adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        implOnUnmappableCharacter(newAction);
602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this;
603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
60637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes     * Returns the replacement byte array, which is never null or empty.
607adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
608adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final byte[] replacement() {
60937871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        return replacementBytes;
610adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
612adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets the new replacement value.
614f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
615adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method first checks the given replacement's validity, then changes
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the replacement value and finally calls the
617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #implReplaceWith(byte[]) implReplaceWith} method with the given
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * new replacement as argument.
619f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param replacement
621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the replacement byte array, cannot be null or empty, its
622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            length cannot be larger than <code>maxBytesPerChar</code>,
623adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            and it must be legal replacement, which can be justified by
6248454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes     *            calling <code>isLegalReplacement(byte[] replacement)</code>.
625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this encoder.
626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the given replacement cannot satisfy the requirement
628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             mentioned above.
629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final CharsetEncoder replaceWith(byte[] replacement) {
63157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        if (replacement == null) {
63257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes            throw new IllegalArgumentException("replacement == null");
63357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        }
63437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        if (replacement.length == 0) {
63537871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes            throw new IllegalArgumentException("replacement.length == 0");
63637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        }
63737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        if (replacement.length > maxBytesPerChar()) {
638126ab1b546c71137a97cef68cc89267e7f7be634Elliott Hughes            throw new IllegalArgumentException("replacement.length > maxBytesPerChar: " +
63937871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes                    replacement.length + " > " + maxBytesPerChar());
64057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        }
64157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        if (!isLegalReplacement(replacement)) {
642126ab1b546c71137a97cef68cc89267e7f7be634Elliott Hughes            throw new IllegalArgumentException("Bad replacement: " + Arrays.toString(replacement));
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
644c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        // It seems like a bug, but the RI doesn't clone, and we have tests that check we don't.
64537871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        this.replacementBytes = replacement;
64637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        implReplaceWith(replacementBytes);
64737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        return this;
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
6510f702e293cb57da788261a80abc84391543f6791Elliott Hughes     * Resets this encoder. This method will reset the internal state and then
6520f702e293cb57da788261a80abc84391543f6791Elliott Hughes     * calls {@link #implReset} to reset any state related to the
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * specific charset.
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final CharsetEncoder reset() {
6560f702e293cb57da788261a80abc84391543f6791Elliott Hughes        state = RESET;
657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        implReset();
658adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this;
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
66237871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes     * Returns this encoder's <code>CodingErrorAction</code> when unmappable
663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * character occurred during encoding process.
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public CodingErrorAction unmappableCharacterAction() {
66637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        return unmappableCharacterAction;
667adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
6680f702e293cb57da788261a80abc84391543f6791Elliott Hughes
6690f702e293cb57da788261a80abc84391543f6791Elliott Hughes    private IllegalStateException illegalStateException() {
6700f702e293cb57da788261a80abc84391543f6791Elliott Hughes        throw new IllegalStateException("State: " + state);
6710f702e293cb57da788261a80abc84391543f6791Elliott Hughes    }
672adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
673