CharsetEncoder.java revision 57a151cc43ef3dfc1040fad5581836c66c8e53f3
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
1957a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughesimport com.ibm.icu4jni.charset.CharsetEncoderICU;
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.BufferOverflowException;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.BufferUnderflowException;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.ByteBuffer;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.CharBuffer;
248454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughesimport java.util.Arrays;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
2757a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * Transforms a sequence of 16-bit Java characters to a byte sequence in some encoding.
2857a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes *
2957a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>The input character sequence is a {@link java.nio.CharBuffer CharBuffer} and the
3057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * output byte sequence is a {@link java.nio.ByteBuffer ByteBuffer}.
3157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes *
3257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>Use {@link #encode(CharBuffer)} to encode an entire {@code CharBuffer} to a
3357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * new {@code ByteBuffer}, or {@link #encode(CharBuffer, ByteBuffer, boolean)} for more
3457a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * control. When using the latter method, the entire operation proceeds as follows:
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <ol>
3657a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <li>Invoke {@link #reset()} to reset the encoder if this instance has been used before.</li>
3757a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <li>Invoke {@link #encode(CharBuffer, ByteBuffer, boolean) encode} with the {@code endOfInput}
3857a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * parameter set to false until additional input is not needed (as signaled by the return value).
3957a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * The input buffer must be filled and the output buffer must be flushed between invocations.
4057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>The {@link #encode(CharBuffer, ByteBuffer, boolean) encode} method will
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * convert as many characters as possible, and the process won't stop until the
4257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * input buffer has been exhausted, the output buffer has been filled, or an
4357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * error has occurred. A {@link CoderResult CoderResult} instance will be
4457a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * returned to indicate the current state. The caller should fill the input buffer, flush
4557a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * the output buffer, or recovering from an error and try again, accordingly.
4657a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * </li>
4757a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <li>Invoke {@link #encode(CharBuffer, ByteBuffer, boolean) encode} for the last time with
4857a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * {@code endOfInput} set to true.</li>
4957a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <li>Invoke {@link #flush(ByteBuffer)} to flush remaining output.</li>
5057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * </ol>
5157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes *
5257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>There are two classes of encoding error: <i>malformed input</i>
5357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * signifies that the input character sequence is not legal, while <i>unmappable character</i>
5457a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * signifies that the input is legal but cannot be mapped to a byte sequence (because the charset
5557a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * cannot represent the character, for example).
5657a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes *
5757a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>Errors can be handled in three ways. The default is to
5857a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * {@link CodingErrorAction.REPORT report} the error to the caller. The alternatives are to
5957a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * {@link CodingErrorAction.IGNORE ignore} the error or {@link CodingErrorAction.IGNORE replace}
6057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * the problematic input with the byte sequence returned by {@link #replacement}. The disposition
6157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * for each of the two kinds of error can be set independently using the {@link #onMalformedInput}
6257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * and {@link #onUnmappableCharacter} methods.
6357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes *
6457a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>The default replacement bytes depend on the charset but can be overridden using the
6557a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * {@link #replaceWith} method.
6657a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes *
6757a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>This class is abstract and encapsulates many common operations of the
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * encoding process for all charsets. Encoders for a specific charset should
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * extend this class and need only to implement the
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@link #encodeLoop(CharBuffer, ByteBuffer) encodeLoop} method for basic
7157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * encoding. If a subclass maintains internal state, it should also override the
7257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * {@link #implFlush(ByteBuffer) implFlush} and {@link #implReset() implReset} methods.
7357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes *
7457a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes * <p>This class is not thread-safe.
75eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson *
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see java.nio.charset.Charset
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see java.nio.charset.CharsetDecoder
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic abstract class CharsetEncoder {
80eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * internal status consts
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int INIT = 0;
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int ONGOING = 1;
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int END = 2;
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int FLUSH = 3;
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // the Charset which creates this encoder
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Charset cs;
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // average bytes per character created by this encoder
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private float averBytes;
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // maximum bytes per character can be created by this encoder
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private float maxBytes;
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // replacement byte array
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private byte[] replace;
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // internal status
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int status;
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // action for malformed input
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private CodingErrorAction malformAction;
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // action for unmapped char input
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private CodingErrorAction unmapAction;
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // decoder instance for this encoder's charset, used for replacement value
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // checking
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private CharsetDecoder decoder;
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
118c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes     * Constructs a new {@code CharsetEncoder} using the given parameters and
119c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes     * the replacement byte array {@code { (byte) '?' }}.
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
121cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes    protected CharsetEncoder(Charset cs, float averageBytesPerChar, float maxBytesPerChar) {
122cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes        this(cs, averageBytesPerChar, maxBytesPerChar, new byte[] { (byte) '?' });
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new <code>CharsetEncoder</code> using the given
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>Charset</code>, replacement byte array, average number and
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * maximum number of bytes created by this encoder for one input character.
129f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param cs
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the <code>Charset</code> to be used by this encoder.
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param averageBytesPerChar
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            average number of bytes created by this encoder for one single
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            input character, must be positive.
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param maxBytesPerChar
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            maximum number of bytes which can be created by this encoder
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            for one single input character, must be positive.
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param replacement
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the replacement byte array, cannot be null or empty, its
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            length cannot be larger than <code>maxBytesPerChar</code>,
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            and must be a legal replacement, which can be justified by
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            {@link #isLegalReplacement(byte[]) isLegalReplacement}.
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if any parameters are invalid.
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected CharsetEncoder(Charset cs, float averageBytesPerChar,
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            float maxBytesPerChar, byte[] replacement) {
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (averageBytesPerChar <= 0 || maxBytesPerChar <= 0) {
1498454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalArgumentException("averageBytesPerChar and maxBytesPerChar must both be positive");
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (averageBytesPerChar > maxBytesPerChar) {
1528454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalArgumentException("averageBytesPerChar is greater than maxBytesPerChar");
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.cs = cs;
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        averBytes = averageBytesPerChar;
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        maxBytes = maxBytesPerChar;
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        status = INIT;
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        malformAction = CodingErrorAction.REPORT;
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        unmapAction = CodingErrorAction.REPORT;
16057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        if (this instanceof CharsetEncoderICU) {
16157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes            // The RI enforces unnecessary restrictions on the replacement bytes. We trust ICU to
16257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes            // know what it's doing. This lets us support EUC-JP, SCSU, and Shift_JIS.
16357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes            uncheckedReplaceWith(replacement);
16457a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        } else {
16557a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes            replaceWith(replacement);
16657a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        }
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the average number of bytes created by this encoder for a single
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * input character.
172f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the average number of bytes created by this encoder for a single
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         input character.
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final float averageBytesPerChar() {
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return averBytes;
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Checks if the given character can be encoded by this encoder.
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Note that this method can change the internal status of this encoder, so
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * it should not be called when another encoding process is ongoing,
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * otherwise it will throw an <code>IllegalStateException</code>.
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method can be overridden for performance improvement.
188eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param c
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given encoder.
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if given character can be encoded by this encoder.
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalStateException
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if another encode process is ongoing so that the current
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             internal status is neither RESET or FLUSH.
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean canEncode(char c) {
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return implCanEncode(CharBuffer.wrap(new char[] { c }));
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // implementation of canEncode
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean implCanEncode(CharBuffer cb) {
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (status == FLUSH) {
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            status = INIT;
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (status != INIT) {
2068454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalStateException("encoding already in progress");
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CodingErrorAction malformBak = malformAction;
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CodingErrorAction unmapBak = unmapAction;
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        onMalformedInput(CodingErrorAction.REPORT);
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        onUnmappableCharacter(CodingErrorAction.REPORT);
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        boolean result = true;
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.encode(cb);
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (CharacterCodingException e) {
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            result = false;
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        onMalformedInput(malformBak);
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        onUnmappableCharacter(unmapBak);
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        reset();
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Checks if a given <code>CharSequence</code> can be encoded by this
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * encoder.
227f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Note that this method can change the internal status of this encoder, so
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * it should not be called when another encode process is ongoing, otherwise
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * it will throw an <code>IllegalStateException</code>.
231f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method can be overridden for performance improvement.
233f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param sequence
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given <code>CharSequence</code>.
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if the given <code>CharSequence</code> can be encoded by
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         this encoder.
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalStateException
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if current internal status is neither RESET or FLUSH.
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean canEncode(CharSequence sequence) {
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CharBuffer cb;
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (sequence instanceof CharBuffer) {
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            cb = ((CharBuffer) sequence).duplicate();
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            cb = CharBuffer.wrap(sequence);
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return implCanEncode(cb);
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the <code>Charset</code> which this encoder uses.
253f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the <code>Charset</code> which this encoder uses.
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final Charset charset() {
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return cs;
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This is a facade method for the encoding operation.
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method encodes the remaining character sequence of the given
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * character buffer into a new byte buffer. This method performs a complete
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * encoding operation, resets at first, then encodes, and flushes at last.
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method should not be invoked if another encode operation is ongoing.
268eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the input buffer.
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a new <code>ByteBuffer</code> containing the bytes produced by
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         this encoding operation. The buffer's limit will be the position
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         of the last byte in the buffer, and the position will be zero.
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalStateException
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if another encoding operation is ongoing.
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws MalformedInputException
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an illegal input character sequence for this charset is
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             encountered, and the action for malformed error is
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws UnmappableCharacterException
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if a legal but unmappable input character sequence for this
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             charset is encountered, and the action for unmappable
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             character error is
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}.
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             Unmappable means the Unicode character sequence at the input
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             buffer's current position cannot be mapped to a equivalent
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             byte sequence.
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws CharacterCodingException
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if other exception happened during the encode operation.
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
29157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes    public final ByteBuffer encode(CharBuffer in) throws CharacterCodingException {
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (in.remaining() == 0) {
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return ByteBuffer.allocate(0);
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        reset();
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int length = (int) (in.remaining() * averBytes);
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ByteBuffer output = ByteBuffer.allocate(length);
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CoderResult result = null;
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (true) {
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            result = encode(in, output, false);
301eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            if (result==CoderResult.UNDERFLOW) {
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
303eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            } else if (result==CoderResult.OVERFLOW) {
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                output = allocateMore(output);
305eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                continue;
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
307eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            checkCoderResult(result);
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        result = encode(in, output, true);
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkCoderResult(result);
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (true) {
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            result = flush(output);
314eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            if (result==CoderResult.UNDERFLOW) {
315eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                output.flip();
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
317eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            } else if (result==CoderResult.OVERFLOW) {
318eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                output = allocateMore(output);
319eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                continue;
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
321eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            checkCoderResult(result);
322eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            output.flip();
323eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            if (result.isMalformed()) {
324eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                throw new MalformedInputException(result.length());
325eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            } else if (result.isUnmappable()) {
326eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                throw new UnmappableCharacterException(result.length());
327eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            }
328eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            break;
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        status = FLUSH;
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return output;
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * checks the result whether it needs to throw CharacterCodingException.
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
33757a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes    private void checkCoderResult(CoderResult result) throws CharacterCodingException {
338eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        if (malformAction == CodingErrorAction.REPORT && result.isMalformed() ) {
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new MalformedInputException(result.length());
340eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        } else if (unmapAction == CodingErrorAction.REPORT && result.isUnmappable()) {
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new UnmappableCharacterException(result.length());
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // allocate more spaces to the given ByteBuffer
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private ByteBuffer allocateMore(ByteBuffer output) {
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (output.capacity() == 0) {
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return ByteBuffer.allocate(1);
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ByteBuffer result = ByteBuffer.allocate(output.capacity() * 2);
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        output.flip();
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        result.put(output);
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Encodes characters starting at the current position of the given input
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * buffer, and writes the equivalent byte sequence into the given output
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * buffer from its current position.
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The buffers' position will be changed with the reading and writing
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * operation, but their limits and marks will be kept intact.
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * A <code>CoderResult</code> instance will be returned according to
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * following rules:
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <ul>
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>A {@link CoderResult#malformedForLength(int) malformed input} result
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * indicates that some malformed input error was encountered, and the
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * erroneous characters start at the input buffer's position and their
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * number can be got by result's {@link CoderResult#length() length}. This
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * kind of result can be returned only if the malformed action is
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}.</li>
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>{@link CoderResult#UNDERFLOW CoderResult.UNDERFLOW} indicates that
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * as many characters as possible in the input buffer have been encoded. If
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * there is no further input and no characters left in the input buffer then
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * this task is complete. If this is not the case then the client should
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * call this method again supplying some more input characters.</li>
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>{@link CoderResult#OVERFLOW CoderResult.OVERFLOW} indicates that the
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * output buffer has been filled, while there are still some characters
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * remaining in the input buffer. This method should be invoked again with a
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * non-full output buffer.</li>
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>A {@link CoderResult#unmappableForLength(int) unmappable character}
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * result indicates that some unmappable character error was encountered,
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * and the erroneous characters start at the input buffer's position and
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * their number can be got by result's {@link CoderResult#length() length}.
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This kind of result can be returned only on
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}.</li>
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * </ul>
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The <code>endOfInput</code> parameter indicates if the invoker can
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * provider further input. This parameter is true if and only if the
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * characters in the current input buffer are all inputs for this encoding
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * operation. Note that it is common and won't cause an error if the invoker
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * sets false and then has no more input available, while it may cause an
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * error if the invoker always sets true in several consecutive invocations.
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This would make the remaining input to be treated as malformed input.
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * input.
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method invokes the
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #encodeLoop(CharBuffer, ByteBuffer) encodeLoop} method to
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * implement the basic encode logic for a specific charset.
402eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the input buffer.
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the output buffer.
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param endOfInput
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            true if all the input characters have been provided.
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a <code>CoderResult</code> instance indicating the result.
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalStateException
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the encoding operation has already started or no more
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             input is needed in this encoding process.
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws CoderMalfunctionError
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             If the {@link #encodeLoop(CharBuffer, ByteBuffer) encodeLoop}
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             method threw an <code>BufferUnderflowException</code> or
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             <code>BufferUnderflowException</code>.
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
418cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes    public final CoderResult encode(CharBuffer in, ByteBuffer out, boolean endOfInput) {
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if ((status == FLUSH) || (!endOfInput && status == END)) {
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalStateException();
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CoderResult result;
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (true) {
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                result = encodeLoop(in, out);
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (BufferOverflowException e) {
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new CoderMalfunctionError(e);
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (BufferUnderflowException e) {
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new CoderMalfunctionError(e);
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
432eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            if (result==CoderResult.UNDERFLOW) {
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                status = endOfInput ? END : ONGOING;
434eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                if (endOfInput) {
435eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    int remaining = in.remaining();
436eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    if (remaining > 0) {
437eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                        result = CoderResult.malformedForLength(remaining);
438eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    } else {
439eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                        return result;
440eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    }
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return result;
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
444eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            } else if (result==CoderResult.OVERFLOW) {
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                status = endOfInput ? END : ONGOING;
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return result;
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            CodingErrorAction action = malformAction;
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (result.isUnmappable()) {
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                action = unmapAction;
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // If the action is IGNORE or REPLACE, we should continue
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // encoding.
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (action == CodingErrorAction.REPLACE) {
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (out.remaining() < replace.length) {
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return CoderResult.OVERFLOW;
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                out.put(replace);
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (action != CodingErrorAction.IGNORE) {
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return result;
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            in.position(in.position() + result.length());
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Encodes characters into bytes. This method is called by
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #encode(CharBuffer, ByteBuffer, boolean) encode}.
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method will implement the essential encoding operation, and it won't
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * stop encoding until either all the input characters are read, the output
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * buffer is filled, or some exception is encountered. Then it will
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * return a <code>CoderResult</code> object indicating the result of the
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * current encoding operation. The rule to construct the
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>CoderResult</code> is the same as for
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #encode(CharBuffer, ByteBuffer, boolean) encode}. When an
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * exception is encountered in the encoding operation, most implementations
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * of this method will return a relevant result object to the
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #encode(CharBuffer, ByteBuffer, boolean) encode} method, and some
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * performance optimized implementation may handle the exception and
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * implement the error action itself.
484eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * <p>
485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The buffers are scanned from their current positions, and their positions
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * will be modified accordingly, while their marks and limits will be
487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * intact. At most {@link CharBuffer#remaining() in.remaining()} characters
488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * will be read, and {@link ByteBuffer#remaining() out.remaining()} bytes
489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * will be written.
490eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * <p>
491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Note that some implementations may pre-scan the input buffer and return
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>CoderResult.UNDERFLOW</code> until it receives sufficient input.
493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the input buffer.
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the output buffer.
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a <code>CoderResult</code> instance indicating the result.
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected abstract CoderResult encodeLoop(CharBuffer in, ByteBuffer out);
501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
502adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Flushes this encoder.
504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method will call {@link #implFlush(ByteBuffer) implFlush}. Some
506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * encoders may need to write some bytes to the output buffer when they have
507adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * read all input characters, subclasses can overridden
508adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #implFlush(ByteBuffer) implFlush} to perform writing action.
509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The maximum number of written bytes won't larger than
511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link ByteBuffer#remaining() out.remaining()}. If some encoder wants to
512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * write more bytes than the output buffer's available remaining space, then
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>CoderResult.OVERFLOW</code> will be returned, and this method
514adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * must be called again with a byte buffer that has free space. Otherwise
515adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * this method will return <code>CoderResult.UNDERFLOW</code>, which
516adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * means one encoding process has been completed successfully.
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
518adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * During the flush, the output buffer's position will be changed
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * accordingly, while its mark and limit will be intact.
520f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out
522adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given output buffer.
523adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return <code>CoderResult.UNDERFLOW</code> or
524adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         <code>CoderResult.OVERFLOW</code>.
525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalStateException
526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if this encoder hasn't read all input characters during one
527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             encoding process, which means neither after calling
528adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             {@link #encode(CharBuffer) encode(CharBuffer)} nor after
529f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *             calling {@link #encode(CharBuffer, ByteBuffer, boolean)
530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             encode(CharBuffer, ByteBuffer, boolean)} with {@code true}
531adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             for the last boolean parameter.
532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final CoderResult flush(ByteBuffer out) {
534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (status != END && status != INIT) {
535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalStateException();
536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CoderResult result = implFlush(out);
538adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (result == CoderResult.UNDERFLOW) {
539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            status = FLUSH;
540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
541adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
543adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
545adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Flushes this encoder. The default implementation does nothing and always
546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * returns <code>CoderResult.UNDERFLOW</code>; this method can be
547adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * overridden if needed.
548f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
549adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out
550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the output buffer.
551adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return <code>CoderResult.UNDERFLOW</code> or
552adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         <code>CoderResult.OVERFLOW</code>.
553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
554adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected CoderResult implFlush(ByteBuffer out) {
555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return CoderResult.UNDERFLOW;
556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
558adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Notifies that this encoder's <code>CodingErrorAction</code> specified
560adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for malformed input error has been changed. The default implementation
561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * does nothing; this method can be overridden if needed.
562f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
563adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param newAction
564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new action.
565adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void implOnMalformedInput(CodingErrorAction newAction) {
567adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // default implementation is empty
568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
569adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Notifies that this encoder's <code>CodingErrorAction</code> specified
572adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for unmappable character error 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 newAction
576adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new action.
577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void implOnUnmappableCharacter(CodingErrorAction newAction) {
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     * Notifies that this encoder's replacement has been changed. The default
584adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * implementation does nothing; this method can be overridden if needed.
585f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
586adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param newReplacement
587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new replacement string.
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
589adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void implReplaceWith(byte[] newReplacement) {
590adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // default implementation is empty
591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
592adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
593adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
594adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Resets this encoder's charset related state. The default implementation
595adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * does nothing; this method can be overridden if needed.
596adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
597adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void implReset() {
598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // default implementation is empty
599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
600adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
601adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Checks if the given argument is legal as this encoder's replacement byte
603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * array.
604f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The given byte array is legal if and only if it can be decode into
606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * sixteen bits Unicode characters.
607f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
608adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method can be overridden for performance improvement.
609f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
61057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes     * @param replacement
611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given byte array to be checked.
612adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if the the given argument is legal as this encoder's
613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         replacement byte array.
614adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
61557a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes    public boolean isLegalReplacement(byte[] replacement) {
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (decoder == null) {
617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            decoder = cs.newDecoder();
61857a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes            decoder.onMalformedInput(CodingErrorAction.REPORT);
61957a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes            decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
62157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        ByteBuffer in = ByteBuffer.wrap(replacement);
62257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        CharBuffer out = CharBuffer.allocate((int) (replacement.length * decoder.maxCharsPerByte()));
623adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        CoderResult result = decoder.decode(in, out, true);
624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return !result.isError();
625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets this encoder's <code>CodingErrorAction</code> when a malformed
629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * input error occurred during the encoding process.
630f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this encoder's <code>CodingErrorAction</code> when a malformed
632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         input error occurred during the encoding process.
633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public CodingErrorAction malformedInputAction() {
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return malformAction;
636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the maximum number of bytes which can be created by this encoder for
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * one input character, must be positive.
641f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the maximum number of bytes which can be created by this encoder
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         for one input character, must be positive.
644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final float maxBytesPerChar() {
646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return maxBytes;
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets this encoder's action on malformed input error.
651f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method will call the
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #implOnMalformedInput(CodingErrorAction) implOnMalformedInput}
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * method with the given new action as argument.
655f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param newAction
657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new action on malformed input error.
658adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this encoder.
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the given newAction is null.
661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final CharsetEncoder onMalformedInput(CodingErrorAction newAction) {
6638454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes        if (newAction == null) {
6648454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalArgumentException("newAction == null");
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        malformAction = newAction;
667adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        implOnMalformedInput(newAction);
668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this;
669adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
671adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
672adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets this encoder's action on unmappable character error.
673f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method will call the
675adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #implOnUnmappableCharacter(CodingErrorAction) implOnUnmappableCharacter}
676adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * method with the given new action as argument.
677f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param newAction
679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the new action on unmappable character error.
680adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this encoder.
681adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the given newAction is null.
683adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
6848454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes    public final CharsetEncoder onUnmappableCharacter(CodingErrorAction newAction) {
6858454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes        if (newAction == null) {
6868454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalArgumentException("newAction == null");
687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        unmapAction = newAction;
689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        implOnUnmappableCharacter(newAction);
690adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this;
691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the replacement byte array, which is never null or empty.
695f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
696adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the replacement byte array, cannot be null or empty.
697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
698adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final byte[] replacement() {
699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return replace;
700adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
702adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
703adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets the new replacement value.
704f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
705adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This method first checks the given replacement's validity, then changes
706adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the replacement value and finally calls the
707adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #implReplaceWith(byte[]) implReplaceWith} method with the given
708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * new replacement as argument.
709f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
710adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param replacement
711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the replacement byte array, cannot be null or empty, its
712adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            length cannot be larger than <code>maxBytesPerChar</code>,
713adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            and it must be legal replacement, which can be justified by
7148454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes     *            calling <code>isLegalReplacement(byte[] replacement)</code>.
715adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this encoder.
716adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
717adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the given replacement cannot satisfy the requirement
718adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             mentioned above.
719adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final CharsetEncoder replaceWith(byte[] replacement) {
72157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        if (replacement == null) {
72257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes            throw new IllegalArgumentException("replacement == null");
72357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        }
72457a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        if (replacement.length == 0 || maxBytes < replacement.length) {
72557a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes            throw new IllegalArgumentException("bad replacement length: " + replacement.length);
72657a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        }
72757a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        if (!isLegalReplacement(replacement)) {
7288454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            throw new IllegalArgumentException("bad replacement: " + Arrays.toString(replacement));
729adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
73057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        uncheckedReplaceWith(replacement);
73157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        return this;
73257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes    }
73357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes
73457a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes    private final void uncheckedReplaceWith(byte[] replacement) {
735c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        // It seems like a bug, but the RI doesn't clone, and we have tests that check we don't.
736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        replace = replacement;
737c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        implReplaceWith(replace);
738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
739adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Resets this encoder. This method will reset the internal status and then
742adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * calla <code>implReset()</code> to reset any status related to the
743adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * specific charset.
744f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
745adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this encoder.
746adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
747adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final CharsetEncoder reset() {
748adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        status = INIT;
749adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        implReset();
750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this;
751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
752adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
754adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets this encoder's <code>CodingErrorAction</code> when unmappable
755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * character occurred during encoding process.
756f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this encoder's <code>CodingErrorAction</code> when unmappable
758adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         character occurred during encoding process.
759adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public CodingErrorAction unmappableCharacterAction() {
761adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return unmapAction;
762adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
763adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
764