1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*******************************************************************************
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* Copyright (C) 1996-2006, International Business Machines Corporation and    *
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* others. All Rights Reserved.                                                  *
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*******************************************************************************
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*******************************************************************************
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*/
9f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes/**
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * A JNI interface for ICU converters.
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
12f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @author Ram Viswanadha, IBM
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
153664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughespackage java.nio.charset;
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.ByteBuffer;
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.CharBuffer;
197d52d787302b862019da41aa753646d88d43fd61Elliott Hughesimport java.util.HashMap;
207d52d787302b862019da41aa753646d88d43fd61Elliott Hughesimport java.util.Map;
215ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughesimport libcore.icu.ICU;
223664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughesimport libcore.icu.NativeConverter;
2326ce8fbd8fe488cc969b08f64c56525662763dc4Jesse Wilsonimport libcore.util.EmptyArray;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
254fd8ac297725190c6d81e9538b1faf7cfb0f5bb8Elliott Hughesfinal class CharsetEncoderICU extends CharsetEncoder {
267d52d787302b862019da41aa753646d88d43fd61Elliott Hughes    private static final Map<String, byte[]> DEFAULT_REPLACEMENTS = new HashMap<String, byte[]>();
277d52d787302b862019da41aa753646d88d43fd61Elliott Hughes    static {
2857a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        // ICU has different default replacements to the RI in some cases. There are many
2957a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        // additional cases, but this covers all the charsets that Java guarantees will be
3057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        // available, which is where compatibility seems most important. (The RI even uses
3157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        // the byte corresponding to '?' in ASCII as the replacement byte for charsets where that
3257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes        // byte corresponds to an entirely different character.)
33d6db7651bf7868ff780d284eb1bfd6ad860ddc1fElliott Hughes        // It's odd that UTF-8 doesn't use U+FFFD, given that (unlike ISO-8859-1 and US-ASCII) it
34d6db7651bf7868ff780d284eb1bfd6ad860ddc1fElliott Hughes        // can represent it, but this is what the RI does...
357d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        byte[] questionMark = new byte[] { (byte) '?' };
367d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        DEFAULT_REPLACEMENTS.put("UTF-8",      questionMark);
377d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        DEFAULT_REPLACEMENTS.put("ISO-8859-1", questionMark);
387d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        DEFAULT_REPLACEMENTS.put("US-ASCII",   questionMark);
397d52d787302b862019da41aa753646d88d43fd61Elliott Hughes    }
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
41c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    private static final int INPUT_OFFSET = 0;
42c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    private static final int OUTPUT_OFFSET = 1;
43c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    private static final int INVALID_CHARS = 2;
44c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    /*
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * data[INPUT_OFFSET]   = on input contains the start of input and on output the number of input chars consumed
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * data[OUTPUT_OFFSET]  = on input contains the start of output and on output the number of output bytes written
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * data[INVALID_CHARS]  = number of invalid chars
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
4933604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes    private int[] data = new int[3];
502981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /* handle to the ICU converter that is opened */
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private long converterHandle=0;
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private char[] input = null;
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private byte[] output = null;
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
579932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda    private char[] allocatedInput = null;
589932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda    private byte[] allocatedOutput = null;
599932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda
60866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    // These instance variables are always assigned in the methods before being used. This class
61866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    // is inherently thread-unsafe so we don't have to worry about synchronization.
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int inEnd;
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int outEnd;
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
657d52d787302b862019da41aa753646d88d43fd61Elliott Hughes    public static CharsetEncoderICU newInstance(Charset cs, String icuCanonicalName) {
667d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        // This complexity is necessary to ensure that even if the constructor, superclass
677d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        // constructor, or call to updateCallback throw, we still free the native peer.
687d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        long address = 0;
697d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        try {
707d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            address = NativeConverter.openConverter(icuCanonicalName);
717d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            float averageBytesPerChar = NativeConverter.getAveBytesPerChar(address);
727d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            float maxBytesPerChar = NativeConverter.getMaxBytesPerChar(address);
737d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            byte[] replacement = makeReplacement(icuCanonicalName, address);
747d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            CharsetEncoderICU result = new CharsetEncoderICU(cs, averageBytesPerChar, maxBytesPerChar, replacement, address);
757d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            address = 0; // CharsetEncoderICU has taken ownership; its finalizer will do the free.
767d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            return result;
777d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        } finally {
787d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            if (address != 0) {
797d52d787302b862019da41aa753646d88d43fd61Elliott Hughes                NativeConverter.closeConverter(address);
807d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            }
817d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        }
827d52d787302b862019da41aa753646d88d43fd61Elliott Hughes    }
837d52d787302b862019da41aa753646d88d43fd61Elliott Hughes
847d52d787302b862019da41aa753646d88d43fd61Elliott Hughes    private static byte[] makeReplacement(String icuCanonicalName, long address) {
857d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        // We have our own map of RI-compatible default replacements (where ICU disagrees)...
867d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        byte[] replacement = DEFAULT_REPLACEMENTS.get(icuCanonicalName);
877d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        if (replacement != null) {
887d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            return replacement.clone();
897d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        }
907d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        // ...but fall back to asking ICU.
917d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        return NativeConverter.getSubstitutionBytes(address);
927d52d787302b862019da41aa753646d88d43fd61Elliott Hughes    }
937d52d787302b862019da41aa753646d88d43fd61Elliott Hughes
947d52d787302b862019da41aa753646d88d43fd61Elliott Hughes    private CharsetEncoderICU(Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement, long address) {
953664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes        super(cs, averageBytesPerChar, maxBytesPerChar, replacement, true);
963664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes        // Our native peer needs to know what just happened...
977d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        this.converterHandle = address;
983664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes        updateCallback();
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
10133604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes    @Override protected void implReplaceWith(byte[] newReplacement) {
1023664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes        updateCallback();
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
10533604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes    @Override protected void implOnMalformedInput(CodingErrorAction newAction) {
106cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes        updateCallback();
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
10933604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes    @Override protected void implOnUnmappableCharacter(CodingErrorAction newAction) {
110cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes        updateCallback();
111cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes    }
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
113cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes    private void updateCallback() {
1145ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes        NativeConverter.setCallbackEncode(converterHandle, this);
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
11733604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes    @Override protected void implReset() {
11833604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes        NativeConverter.resetCharToByte(converterHandle);
11933604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes        data[INPUT_OFFSET] = 0;
12033604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes        data[OUTPUT_OFFSET] = 0;
12133604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes        data[INVALID_CHARS] = 0;
1222981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        output = null;
1232981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        input = null;
1242981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        allocatedInput = null;
1252981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        allocatedOutput = null;
1262981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        inEnd = 0;
1272981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        outEnd = 0;
12833604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes    }
12933604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes
13033604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes    @Override protected CoderResult implFlush(ByteBuffer out) {
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
13233604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes            // ICU needs to see an empty input.
13333604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes            input = EmptyArray.CHAR;
134dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes            inEnd = 0;
13533604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes            data[INPUT_OFFSET] = 0;
13633604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            data[OUTPUT_OFFSET] = getArray(out);
13833604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes            data[INVALID_CHARS] = 0; // Make sure we don't see earlier errors.
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1405ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes            int error = NativeConverter.encode(converterHandle, input, inEnd, output, outEnd, data, true);
1415ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes            if (ICU.U_FAILURE(error)) {
1425ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return CoderResult.OVERFLOW;
1445ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                } else if (error == ICU.U_TRUNCATED_CHAR_FOUND) {
145c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes                    if (data[INPUT_OFFSET] > 0) {
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        return CoderResult.malformedForLength(data[INPUT_OFFSET]);
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return CoderResult.UNDERFLOW;
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } finally {
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setPosition(out);
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            implReset();
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
15733604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes    @Override protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!in.hasRemaining()) {
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return CoderResult.UNDERFLOW;
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        data[INPUT_OFFSET] = getArray(in);
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        data[OUTPUT_OFFSET]= getArray(out);
164f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        data[INVALID_CHARS] = 0; // Make sure we don't see earlier errors.
165f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
1675ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes            int error = NativeConverter.encode(converterHandle, input, inEnd, output, outEnd, data, false);
1685ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes            if (ICU.U_FAILURE(error)) {
1695ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return CoderResult.OVERFLOW;
1715ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                } else if (error == ICU.U_INVALID_CHAR_FOUND) {
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return CoderResult.unmappableForLength(data[INVALID_CHARS]);
1735ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                } else if (error == ICU.U_ILLEGAL_CHAR_FOUND) {
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return CoderResult.malformedForLength(data[INVALID_CHARS]);
17533604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes                } else {
1765ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                    throw new AssertionError(error);
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1792981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            // Decoding succeeded: give us more data.
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return CoderResult.UNDERFLOW;
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } finally {
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setPosition(in);
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setPosition(out);
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean canEncode(char c) {
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return canEncode((int) c);
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
191866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    public boolean canEncode(int codePoint) {
192866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes        return NativeConverter.canEncode(converterHandle, codePoint);
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
195e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected void finalize() throws Throwable {
196e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        try {
197e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            NativeConverter.closeConverter(converterHandle);
198e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            converterHandle=0;
199e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
200e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            super.finalize();
201e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        }
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
204866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    private int getArray(ByteBuffer out) {
205866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes        if (out.hasArray()) {
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            output = out.array();
207b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes            outEnd = out.arrayOffset() + out.limit();
208b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes            return out.arrayOffset() + out.position();
209866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes        } else {
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            outEnd = out.remaining();
2112981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            if (allocatedOutput == null || outEnd > allocatedOutput.length) {
2129932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda                allocatedOutput = new byte[outEnd];
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
21433604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes            // The array's start position is 0
2159932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda            output = allocatedOutput;
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
220866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    private int getArray(CharBuffer in) {
221866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes        if (in.hasArray()) {
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            input = in.array();
223b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes            inEnd = in.arrayOffset() + in.limit();
22433604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes            return in.arrayOffset() + in.position();
225866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes        } else {
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            inEnd = in.remaining();
22733604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes            if (allocatedInput == null || inEnd > allocatedInput.length) {
2289932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda                allocatedInput = new char[inEnd];
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
23033604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes            // Copy the input buffer into the allocated array.
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int pos = in.position();
23233604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes            in.get(allocatedInput, 0, inEnd);
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            in.position(pos);
23433604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes            // The array's start position is 0
23533604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes            input = allocatedInput;
23633604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes            return 0;
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
239f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
24033604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes    private void setPosition(ByteBuffer out) {
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (out.hasArray()) {
242b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes            out.position(out.position() + data[OUTPUT_OFFSET] - out.arrayOffset());
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            out.put(output, 0, data[OUTPUT_OFFSET]);
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
2469932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda        // release reference to output array, which may not be ours
2479932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda        output = null;
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
25033604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes    private void setPosition(CharBuffer in) {
2512981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        in.position(in.position() + data[INPUT_OFFSET] - data[INVALID_CHARS]);
2529932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda        // release reference to input array, which may not be ours
2539932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda        input = null;
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
256