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 {
7930a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes    private static final int READY = 0;
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int ONGOING = 1;
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int END = 2;
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int FLUSH = 3;
8330a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes    private static final int INIT = 4;
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8537871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes    private final Charset cs;
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes    private final float averageBytesPerChar;
8837871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes    private final float maxBytesPerChar;
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9037871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes    private byte[] replacementBytes;
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int status;
9330a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes    // internal status indicates encode(CharBuffer) operation is finished
9430a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes    private boolean finished;
9530a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes
9637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes    private CodingErrorAction malformedInputAction;
9737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes    private CodingErrorAction unmappableCharacterAction;
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9937871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes    // decoder instance for this encoder's charset, used for replacement value checking
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private CharsetDecoder decoder;
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
103c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes     * Constructs a new {@code CharsetEncoder} using the given parameters and
104c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes     * the replacement byte array {@code { (byte) '?' }}.
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
106cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes    protected CharsetEncoder(Charset cs, float averageBytesPerChar, float maxBytesPerChar) {
107cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes        this(cs, averageBytesPerChar, maxBytesPerChar, new byte[] { (byte) '?' });
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new <code>CharsetEncoder</code> using the given
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>Charset</code>, replacement byte array, average number and
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * maximum number of bytes created by this encoder for one input character.
114f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param cs
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the <code>Charset</code> to be used by this encoder.
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param averageBytesPerChar
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            average number of bytes created by this encoder for one single
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            input character, must be positive.
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param maxBytesPerChar
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            maximum number of bytes which can be created by this encoder
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            for one single input character, must be positive.
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param replacement
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the replacement byte array, cannot be null or empty, its
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            length cannot be larger than <code>maxBytesPerChar</code>,
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            and must be a legal replacement, which can be justified by
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            {@link #isLegalReplacement(byte[]) isLegalReplacement}.
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if any parameters are invalid.
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1313664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes    protected CharsetEncoder(Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement) {
1323664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes        this(cs, averageBytesPerChar, maxBytesPerChar, replacement, false);
1333664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes    }
1343664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes
1353664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes    CharsetEncoder(Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement, boolean trusted) {
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (averageBytesPerChar <= 0 || maxBytesPerChar <= 0) {
1378454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalArgumentException("averageBytesPerChar and maxBytesPerChar must both be positive");
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (averageBytesPerChar > maxBytesPerChar) {
1408454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalArgumentException("averageBytesPerChar is greater than maxBytesPerChar");
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.cs = cs;
14337871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        this.averageBytesPerChar = averageBytesPerChar;
14437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        this.maxBytesPerChar = maxBytesPerChar;
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        status = INIT;
14637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        malformedInputAction = CodingErrorAction.REPORT;
14737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        unmappableCharacterAction = CodingErrorAction.REPORT;
1483664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes        if (trusted) {
1493664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes            // The RI enforces unnecessary restrictions on the replacement bytes. We trust ICU to
1503664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes            // know what it's doing. Doing so lets us support ICU's EUC-JP, SCSU, and Shift_JIS.
1513664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes            this.replacementBytes = replacement;
1523664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes        } else {
1533664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes            replaceWith(replacement);
1543664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes        }
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
15837871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes     * Returns the average number of bytes created by this encoder for a single
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * input character.
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final float averageBytesPerChar() {
16237871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        return averageBytesPerChar;
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Checks if the given character can be encoded by this encoder.
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Note that this method can change the internal status of this encoder, so
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * it should not be called when another encoding process is ongoing,
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * otherwise it will throw an <code>IllegalStateException</code>.
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method can be overridden for performance improvement.
173eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param c
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given encoder.
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if given character can be encoded by this encoder.
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalStateException
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if another encode process is ongoing so that the current
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             internal status is neither RESET or FLUSH.
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean canEncode(char c) {
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return implCanEncode(CharBuffer.wrap(new char[] { c }));
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // implementation of canEncode
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean implCanEncode(CharBuffer cb) {
18730a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes        if (status == FLUSH || status == INIT) {
18830a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes            status = READY;
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
19030a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes        if (status != READY) {
1918454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalStateException("encoding already in progress");
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
19337871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        CodingErrorAction malformBak = malformedInputAction;
19437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        CodingErrorAction unmapBak = unmappableCharacterAction;
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        onMalformedInput(CodingErrorAction.REPORT);
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        onUnmappableCharacter(CodingErrorAction.REPORT);
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        boolean result = true;
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.encode(cb);
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (CharacterCodingException e) {
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            result = false;
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        onMalformedInput(malformBak);
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        onUnmappableCharacter(unmapBak);
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        reset();
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Checks if a given <code>CharSequence</code> can be encoded by this
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * encoder.
212f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Note that this method can change the internal status of this encoder, so
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * it should not be called when another encode process is ongoing, otherwise
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * it will throw an <code>IllegalStateException</code>.
216f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method can be overridden for performance improvement.
218f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param sequence
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given <code>CharSequence</code>.
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if the given <code>CharSequence</code> can be encoded by
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         this encoder.
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalStateException
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if current internal status is neither RESET or FLUSH.
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean canEncode(CharSequence sequence) {
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CharBuffer cb;
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (sequence instanceof CharBuffer) {
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            cb = ((CharBuffer) sequence).duplicate();
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            cb = CharBuffer.wrap(sequence);
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return implCanEncode(cb);
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
23737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes     * Returns the {@link Charset} which this encoder uses.
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final Charset charset() {
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return cs;
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This is a facade method for the encoding operation.
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method encodes the remaining character sequence of the given
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * character buffer into a new byte buffer. This method performs a complete
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * encoding operation, resets at first, then encodes, and flushes at last.
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method should not be invoked if another encode operation is ongoing.
251eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the input buffer.
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a new <code>ByteBuffer</code> containing the bytes produced by
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         this encoding operation. The buffer's limit will be the position
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         of the last byte in the buffer, and the position will be zero.
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalStateException
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if another encoding operation is ongoing.
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws MalformedInputException
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an illegal input character sequence for this charset is
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             encountered, and the action for malformed error is
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws UnmappableCharacterException
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if a legal but unmappable input character sequence for this
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             charset is encountered, and the action for unmappable
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             character error is
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}.
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             Unmappable means the Unicode character sequence at the input
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             buffer's current position cannot be mapped to a equivalent
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             byte sequence.
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws CharacterCodingException
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if other exception happened during the encode operation.
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
27457a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes    public final ByteBuffer encode(CharBuffer in) throws CharacterCodingException {
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (in.remaining() == 0) {
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return ByteBuffer.allocate(0);
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        reset();
27937871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        int length = (int) (in.remaining() * averageBytesPerChar);
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ByteBuffer output = ByteBuffer.allocate(length);
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CoderResult result = null;
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (true) {
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            result = encode(in, output, false);
284eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            if (result==CoderResult.UNDERFLOW) {
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
286eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            } else if (result==CoderResult.OVERFLOW) {
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                output = allocateMore(output);
288eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                continue;
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
290eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            checkCoderResult(result);
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        result = encode(in, output, true);
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkCoderResult(result);
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (true) {
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            result = flush(output);
297eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            if (result==CoderResult.UNDERFLOW) {
298eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                output.flip();
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
300eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            } else if (result==CoderResult.OVERFLOW) {
301eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                output = allocateMore(output);
302eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                continue;
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
304eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            checkCoderResult(result);
305eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            output.flip();
306eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            if (result.isMalformed()) {
307eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                throw new MalformedInputException(result.length());
308eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            } else if (result.isUnmappable()) {
309eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                throw new UnmappableCharacterException(result.length());
310eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            }
311eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            break;
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
31330a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes        status = READY;
31430a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes        finished = true;
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return output;
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * checks the result whether it needs to throw CharacterCodingException.
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
32157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes    private void checkCoderResult(CoderResult result) throws CharacterCodingException {
32237871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        if (malformedInputAction == CodingErrorAction.REPORT && result.isMalformed() ) {
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new MalformedInputException(result.length());
32437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        } else if (unmappableCharacterAction == CodingErrorAction.REPORT && result.isUnmappable()) {
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new UnmappableCharacterException(result.length());
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // allocate more spaces to the given ByteBuffer
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private ByteBuffer allocateMore(ByteBuffer output) {
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (output.capacity() == 0) {
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return ByteBuffer.allocate(1);
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ByteBuffer result = ByteBuffer.allocate(output.capacity() * 2);
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        output.flip();
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        result.put(output);
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Encodes characters starting at the current position of the given input
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * buffer, and writes the equivalent byte sequence into the given output
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * buffer from its current position.
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The buffers' position will be changed with the reading and writing
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * operation, but their limits and marks will be kept intact.
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * A <code>CoderResult</code> instance will be returned according to
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * following rules:
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <ul>
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>A {@link CoderResult#malformedForLength(int) malformed input} result
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * indicates that some malformed input error was encountered, and the
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * erroneous characters start at the input buffer's position and their
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * number can be got by result's {@link CoderResult#length() length}. This
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * kind of result can be returned only if the malformed action is
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}.</li>
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>{@link CoderResult#UNDERFLOW CoderResult.UNDERFLOW} indicates that
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * as many characters as possible in the input buffer have been encoded. If
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * there is no further input and no characters left in the input buffer then
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * this task is complete. If this is not the case then the client should
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * call this method again supplying some more input characters.</li>
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>{@link CoderResult#OVERFLOW CoderResult.OVERFLOW} indicates that the
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * output buffer has been filled, while there are still some characters
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * remaining in the input buffer. This method should be invoked again with a
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * non-full output buffer.</li>
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>A {@link CoderResult#unmappableForLength(int) unmappable character}
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * result indicates that some unmappable character error was encountered,
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * and the erroneous characters start at the input buffer's position and
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * their number can be got by result's {@link CoderResult#length() length}.
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This kind of result can be returned only on
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}.</li>
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * </ul>
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The <code>endOfInput</code> parameter indicates if the invoker can
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * provider further input. This parameter is true if and only if the
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * characters in the current input buffer are all inputs for this encoding
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * operation. Note that it is common and won't cause an error if the invoker
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * sets false and then has no more input available, while it may cause an
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * error if the invoker always sets true in several consecutive invocations.
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This would make the remaining input to be treated as malformed input.
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * input.
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method invokes the
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #encodeLoop(CharBuffer, ByteBuffer) encodeLoop} method to
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * implement the basic encode logic for a specific charset.
386eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the input buffer.
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the output buffer.
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param endOfInput
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            true if all the input characters have been provided.
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a <code>CoderResult</code> instance indicating the result.
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalStateException
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the encoding operation has already started or no more
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             input is needed in this encoding process.
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws CoderMalfunctionError
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             If the {@link #encodeLoop(CharBuffer, ByteBuffer) encodeLoop}
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             method threw an <code>BufferUnderflowException</code> or
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             <code>BufferUnderflowException</code>.
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
402cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes    public final CoderResult encode(CharBuffer in, ByteBuffer out, boolean endOfInput) {
40330a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes        // If the previous step is encode(CharBuffer), then no more input is needed
40430a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes        // thus endOfInput should not be false
40530a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes        if (status == READY && finished && !endOfInput) {
40630a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes            throw new IllegalStateException();
40730a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes        }
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if ((status == FLUSH) || (!endOfInput && status == END)) {
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalStateException();
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CoderResult result;
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (true) {
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                result = encodeLoop(in, out);
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (BufferOverflowException e) {
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new CoderMalfunctionError(e);
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (BufferUnderflowException e) {
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new CoderMalfunctionError(e);
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
421eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            if (result==CoderResult.UNDERFLOW) {
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                status = endOfInput ? END : ONGOING;
423eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                if (endOfInput) {
424eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    int remaining = in.remaining();
425eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    if (remaining > 0) {
426eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                        result = CoderResult.malformedForLength(remaining);
427eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    } else {
428eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                        return result;
429eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    }
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return result;
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
433eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            } else if (result==CoderResult.OVERFLOW) {
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                status = endOfInput ? END : ONGOING;
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return result;
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
43737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes            CodingErrorAction action = malformedInputAction;
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (result.isUnmappable()) {
43937871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes                action = unmappableCharacterAction;
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // If the action is IGNORE or REPLACE, we should continue
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // encoding.
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (action == CodingErrorAction.REPLACE) {
44437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes                if (out.remaining() < replacementBytes.length) {
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return CoderResult.OVERFLOW;
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
44737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes                out.put(replacementBytes);
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (action != CodingErrorAction.IGNORE) {
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return result;
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            in.position(in.position() + result.length());
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Encodes characters into bytes. This method is called by
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #encode(CharBuffer, ByteBuffer, boolean) encode}.
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method will implement the essential encoding operation, and it won't
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * stop encoding until either all the input characters are read, the output
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * buffer is filled, or some exception is encountered. Then it will
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * return a <code>CoderResult</code> object indicating the result of the
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * current encoding operation. The rule to construct the
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>CoderResult</code> is the same as for
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #encode(CharBuffer, ByteBuffer, boolean) encode}. When an
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * exception is encountered in the encoding operation, most implementations
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * of this method will return a relevant result object to the
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #encode(CharBuffer, ByteBuffer, boolean) encode} method, and some
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * performance optimized implementation may handle the exception and
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * implement the error action itself.
473eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * <p>
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The buffers are scanned from their current positions, and their positions
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * will be modified accordingly, while their marks and limits will be
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * intact. At most {@link CharBuffer#remaining() in.remaining()} characters
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * will be read, and {@link ByteBuffer#remaining() out.remaining()} bytes
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * will be written.
479eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * <p>
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Note that some implementations may pre-scan the input buffer and return
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>CoderResult.UNDERFLOW</code> until it receives sufficient input.
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in
484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the input buffer.
485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the output buffer.
487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a <code>CoderResult</code> instance indicating the result.
488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected abstract CoderResult encodeLoop(CharBuffer in, ByteBuffer out);
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Flushes this encoder.
493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method will call {@link #implFlush(ByteBuffer) implFlush}. Some
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * encoders may need to write some bytes to the output buffer when they have
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * read all input characters, subclasses can overridden
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #implFlush(ByteBuffer) implFlush} to perform writing action.
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The maximum number of written bytes won't larger than
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link ByteBuffer#remaining() out.remaining()}. If some encoder wants to
501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * write more bytes than the output buffer's available remaining space, then
502adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>CoderResult.OVERFLOW</code> will be returned, and this method
503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * must be called again with a byte buffer that has free space. Otherwise
504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * this method will return <code>CoderResult.UNDERFLOW</code>, which
505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * means one encoding process has been completed successfully.
506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
507adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * During the flush, the output buffer's position will be changed
508adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * accordingly, while its mark and limit will be intact.
509f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out
511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given output buffer.
512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return <code>CoderResult.UNDERFLOW</code> or
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         <code>CoderResult.OVERFLOW</code>.
514adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalStateException
515adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if this encoder hasn't read all input characters during one
516adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             encoding process, which means neither after calling
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             {@link #encode(CharBuffer) encode(CharBuffer)} nor after
518f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *             calling {@link #encode(CharBuffer, ByteBuffer, boolean)
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             encode(CharBuffer, ByteBuffer, boolean)} with {@code true}
520adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             for the last boolean parameter.
521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
522adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final CoderResult flush(ByteBuffer out) {
52330a7ff69872ad0b8de60550a740818b645ba0f29Elliott Hughes        if (status != END && status != READY) {
524adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalStateException();
525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CoderResult result = implFlush(out);
527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (result == CoderResult.UNDERFLOW) {
528adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            status = FLUSH;
529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
531adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Flushes this encoder. The default implementation does nothing and always
535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * returns <code>CoderResult.UNDERFLOW</code>; this method can be
536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * overridden if needed.
537f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
538adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out
539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the output buffer.
540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return <code>CoderResult.UNDERFLOW</code> or
541adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         <code>CoderResult.OVERFLOW</code>.
542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
543adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected CoderResult implFlush(ByteBuffer out) {
544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return CoderResult.UNDERFLOW;
545adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
547adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
548adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Notifies that this encoder's <code>CodingErrorAction</code> specified
549adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for malformed input error has been changed. The default implementation
550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * does nothing; this method can be overridden if needed.
551f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
552adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param newAction
553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new action.
554adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void implOnMalformedInput(CodingErrorAction newAction) {
556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // default implementation is empty
557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
558adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
560adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Notifies that this encoder's <code>CodingErrorAction</code> specified
561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for unmappable character error has been changed. The default
562adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * implementation does nothing; this method can be overridden if needed.
563f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param newAction
565adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new action.
566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
567adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void implOnUnmappableCharacter(CodingErrorAction newAction) {
568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // default implementation is empty
569adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
572adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Notifies that this encoder's replacement has been changed. The default
573adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * implementation does nothing; this method can be overridden if needed.
574f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
575adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param newReplacement
576adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new replacement string.
577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void implReplaceWith(byte[] newReplacement) {
579adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // default implementation is empty
580adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
581adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
582adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Resets this encoder's charset related state. The default implementation
584adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * does nothing; this method can be overridden if needed.
585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
586adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void implReset() {
587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // default implementation is empty
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
589adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
590adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Checks if the given argument is legal as this encoder's replacement byte
592adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * array.
593f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
594adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The given byte array is legal if and only if it can be decode into
595adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * sixteen bits Unicode characters.
596f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
597adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method can be overridden for performance improvement.
598f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
59957a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes     * @param replacement
600adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given byte array to be checked.
601adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if the the given argument is legal as this encoder's
602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         replacement byte array.
603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
60457a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes    public boolean isLegalReplacement(byte[] replacement) {
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (decoder == null) {
606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            decoder = cs.newDecoder();
60757a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes            decoder.onMalformedInput(CodingErrorAction.REPORT);
60857a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes            decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
609adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
61057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        ByteBuffer in = ByteBuffer.wrap(replacement);
61157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        CharBuffer out = CharBuffer.allocate((int) (replacement.length * decoder.maxCharsPerByte()));
612adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CoderResult result = decoder.decode(in, out, true);
613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return !result.isError();
614adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
615adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
61737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes     * Returns this encoder's <code>CodingErrorAction</code> when a malformed
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * input error occurred during the encoding process.
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public CodingErrorAction malformedInputAction() {
62137871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        return malformedInputAction;
622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
623adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
62537871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes     * Returns the maximum number of bytes which can be created by this encoder for
626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * one input character, must be positive.
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final float maxBytesPerChar() {
62937871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        return maxBytesPerChar;
630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets this encoder's action on malformed input error.
634f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method will call the
636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #implOnMalformedInput(CodingErrorAction) implOnMalformedInput}
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * method with the given new action as argument.
638f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param newAction
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new action on malformed input error.
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this encoder.
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the given newAction is null.
644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final CharsetEncoder onMalformedInput(CodingErrorAction newAction) {
6468454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes        if (newAction == null) {
6478454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalArgumentException("newAction == null");
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
64937871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        malformedInputAction = newAction;
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        implOnMalformedInput(newAction);
651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this;
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets this encoder's action on unmappable character error.
656f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method will call the
658adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #implOnUnmappableCharacter(CodingErrorAction) implOnUnmappableCharacter}
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * method with the given new action as argument.
660f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param newAction
662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new action on unmappable character error.
663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this encoder.
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the given newAction is null.
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
6678454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes    public final CharsetEncoder onUnmappableCharacter(CodingErrorAction newAction) {
6688454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes        if (newAction == null) {
6698454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalArgumentException("newAction == null");
670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
67137871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        unmappableCharacterAction = newAction;
672adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        implOnUnmappableCharacter(newAction);
673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this;
674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
675adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
676adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
67737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes     * Returns the replacement byte array, which is never null or empty.
678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final byte[] replacement() {
68037871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        return replacementBytes;
681adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
683adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets the new replacement value.
685f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
686adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method first checks the given replacement's validity, then changes
687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the replacement value and finally calls the
688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #implReplaceWith(byte[]) implReplaceWith} method with the given
689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * new replacement as argument.
690f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param replacement
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the replacement byte array, cannot be null or empty, its
693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            length cannot be larger than <code>maxBytesPerChar</code>,
694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            and it must be legal replacement, which can be justified by
6958454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes     *            calling <code>isLegalReplacement(byte[] replacement)</code>.
696adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this encoder.
697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
698adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the given replacement cannot satisfy the requirement
699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             mentioned above.
700adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final CharsetEncoder replaceWith(byte[] replacement) {
70257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        if (replacement == null) {
70357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes            throw new IllegalArgumentException("replacement == null");
70457a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        }
70537871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        if (replacement.length == 0) {
70637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes            throw new IllegalArgumentException("replacement.length == 0");
70737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        }
70837871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        if (replacement.length > maxBytesPerChar()) {
709126ab1b546c71137a97cef68cc89267e7f7be634Elliott Hughes            throw new IllegalArgumentException("replacement.length > maxBytesPerChar: " +
71037871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes                    replacement.length + " > " + maxBytesPerChar());
71157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        }
71257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        if (!isLegalReplacement(replacement)) {
713126ab1b546c71137a97cef68cc89267e7f7be634Elliott Hughes            throw new IllegalArgumentException("Bad replacement: " + Arrays.toString(replacement));
714adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
715c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        // It seems like a bug, but the RI doesn't clone, and we have tests that check we don't.
71637871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        this.replacementBytes = replacement;
71737871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        implReplaceWith(replacementBytes);
71837871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        return this;
719adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Resets this encoder. This method will reset the internal status and then
72337871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes     * calls <code>implReset()</code> to reset any status related to the
724adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * specific charset.
725f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this encoder.
727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
728adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final CharsetEncoder reset() {
729adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        status = INIT;
730adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        implReset();
731adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this;
732adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
733adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
73537871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes     * Returns this encoder's <code>CodingErrorAction</code> when unmappable
736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * character occurred during encoding process.
737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public CodingErrorAction unmappableCharacterAction() {
73937871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        return unmappableCharacterAction;
740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
742