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*******************************************************************************
8f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes*/
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
177365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.nio.ByteBuffer;
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.CharBuffer;
195ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughesimport libcore.icu.ICU;
203664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughesimport libcore.icu.NativeConverter;
2126ce8fbd8fe488cc969b08f64c56525662763dc4Jesse Wilsonimport libcore.util.EmptyArray;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
234fd8ac297725190c6d81e9538b1faf7cfb0f5bb8Elliott Hughesfinal class CharsetDecoderICU extends CharsetDecoder {
24cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes    private static final int MAX_CHARS_PER_BYTE = 2;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
26c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    private static final int INPUT_OFFSET = 0;
27c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    private static final int OUTPUT_OFFSET = 1;
28c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    private static final int INVALID_BYTES = 2;
29c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    /*
30c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes     * data[INPUT_OFFSET]   = on input contains the start of input and on output the number of input bytes consumed
31c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes     * data[OUTPUT_OFFSET]  = on input contains the start of output and on output the number of output chars written
32c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes     * data[INVALID_BYTES]  = number of invalid bytes
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
342981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes    private int[] data = new int[3];
35f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /* handle to the ICU converter that is opened */
37c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    private long converterHandle = 0;
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
39c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    private byte[] input = null;
40c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    private char[] output= null;
419932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda
429932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda    private byte[] allocatedInput = null;
439932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda    private char[] allocatedOutput = null;
44f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
45866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    // These instance variables are always assigned in the methods before being used. This class
46866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    // is inherently thread-unsafe so we don't have to worry about synchronization.
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int inEnd;
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int outEnd;
49f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
507d52d787302b862019da41aa753646d88d43fd61Elliott Hughes    public static CharsetDecoderICU newInstance(Charset cs, String icuCanonicalName) {
517d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        // This complexity is necessary to ensure that even if the constructor, superclass
527d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        // constructor, or call to updateCallback throw, we still free the native peer.
537d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        long address = 0;
547d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        try {
557d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            address = NativeConverter.openConverter(icuCanonicalName);
567d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            float averageCharsPerByte = NativeConverter.getAveCharsPerByte(address);
577d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            CharsetDecoderICU result = new CharsetDecoderICU(cs, averageCharsPerByte, address);
587d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            address = 0; // CharsetDecoderICU has taken ownership; its finalizer will do the free.
597d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            result.updateCallback();
607d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            return result;
617d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        } finally {
627d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            if (address != 0) {
637d52d787302b862019da41aa753646d88d43fd61Elliott Hughes                NativeConverter.closeConverter(address);
647d52d787302b862019da41aa753646d88d43fd61Elliott Hughes            }
657d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        }
667d52d787302b862019da41aa753646d88d43fd61Elliott Hughes    }
677d52d787302b862019da41aa753646d88d43fd61Elliott Hughes
687d52d787302b862019da41aa753646d88d43fd61Elliott Hughes    private CharsetDecoderICU(Charset cs, float averageCharsPerByte, long address) {
697d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        super(cs, averageCharsPerByte, MAX_CHARS_PER_BYTE);
707d52d787302b862019da41aa753646d88d43fd61Elliott Hughes        this.converterHandle = address;
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
72f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
732981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes    @Override protected void implReplaceWith(String newReplacement) {
7437871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        updateCallback();
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     }
76f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
772981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes    @Override protected final void implOnMalformedInput(CodingErrorAction newAction) {
78cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes        updateCallback();
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
80f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
812981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes    @Override protected final void implOnUnmappableCharacter(CodingErrorAction newAction) {
82cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes        updateCallback();
83cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes    }
84cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes
85cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes    private void updateCallback() {
865ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes        NativeConverter.setCallbackDecode(converterHandle, this);
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
88f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
892981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes    @Override protected void implReset() {
902981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        NativeConverter.resetByteToChar(converterHandle);
912981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        data[INPUT_OFFSET] = 0;
922981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        data[OUTPUT_OFFSET] = 0;
932981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        data[INVALID_BYTES] = 0;
942981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        output = null;
952981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        input = null;
962981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        allocatedInput = null;
972981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        allocatedOutput = null;
982981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        inEnd = 0;
992981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        outEnd = 0;
1002981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes    }
1012981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes
102dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes    @Override protected final CoderResult implFlush(CharBuffer out) {
103c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        try {
104dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes            // ICU needs to see an empty input.
105dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes            input = EmptyArray.BYTE;
106dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes            inEnd = 0;
107dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes            data[INPUT_OFFSET] = 0;
108dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes
109c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes            data[OUTPUT_OFFSET] = getArray(out);
110dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes            data[INVALID_BYTES] = 0; // Make sure we don't see earlier errors.
111dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes
1125ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes            int error = NativeConverter.decode(converterHandle, input, inEnd, output, outEnd, data, true);
1135ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes            if (ICU.U_FAILURE(error)) {
1145ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return CoderResult.OVERFLOW;
1165ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                } else if (error == ICU.U_TRUNCATED_CHAR_FOUND) {
117c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes                    if (data[INPUT_OFFSET] > 0) {
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        return CoderResult.malformedForLength(data[INPUT_OFFSET]);
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return CoderResult.UNDERFLOW;
123c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes       } finally {
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setPosition(out);
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            implReset();
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project       }
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
128f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
129dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes    @Override protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
130dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes        if (!in.hasRemaining()) {
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return CoderResult.UNDERFLOW;
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        data[INPUT_OFFSET] = getArray(in);
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        data[OUTPUT_OFFSET]= getArray(out);
136f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
1372981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        try {
1385ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes            int error = NativeConverter.decode(converterHandle, input, inEnd, output, outEnd, data, false);
1395ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes            if (ICU.U_FAILURE(error)) {
1405ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
1415ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                    return CoderResult.OVERFLOW;
1425ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                } else if (error == ICU.U_INVALID_CHAR_FOUND) {
1435ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                    return CoderResult.unmappableForLength(data[INVALID_BYTES]);
1445ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                } else if (error == ICU.U_ILLEGAL_CHAR_FOUND) {
1455ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                    return CoderResult.malformedForLength(data[INVALID_BYTES]);
1465ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                } else {
1475ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                    throw new AssertionError(error);
1485ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                }
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
150c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes            // Decoding succeeded: give us more data.
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return CoderResult.UNDERFLOW;
152c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        } finally {
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setPosition(in);
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setPosition(out);
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
157f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
158e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected void finalize() throws Throwable {
159e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        try {
160e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            NativeConverter.closeConverter(converterHandle);
161e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            converterHandle = 0;
162e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
163e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            super.finalize();
164e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        }
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
166f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
167866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    private int getArray(CharBuffer out) {
168c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        if (out.hasArray()) {
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            output = out.array();
170b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes            outEnd = out.arrayOffset() + out.limit();
171b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes            return out.arrayOffset() + out.position();
172c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        } else {
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            outEnd = out.remaining();
1742981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            if (allocatedOutput == null || outEnd > allocatedOutput.length) {
1759932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda                allocatedOutput = new char[outEnd];
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1772981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            // The array's start position is 0.
1789932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda            output = allocatedOutput;
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
182c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes
183866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    private  int getArray(ByteBuffer in) {
184c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        if (in.hasArray()) {
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            input = in.array();
186b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes            inEnd = in.arrayOffset() + in.limit();
1872981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            return in.arrayOffset() + in.position();
188c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        } else {
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            inEnd = in.remaining();
1902981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            if (allocatedInput == null || inEnd > allocatedInput.length) {
1919932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda                allocatedInput = new byte[inEnd];
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1932981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            // Copy the input buffer into the allocated array.
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int pos = in.position();
1952981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            in.get(allocatedInput, 0, inEnd);
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            in.position(pos);
1972981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            // The array's start position is 0.
1982981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            input = allocatedInput;
1992981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            return 0;
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
202c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes
203866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    private void setPosition(CharBuffer out) {
204c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        if (out.hasArray()) {
205b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes            out.position(out.position() + data[OUTPUT_OFFSET] - out.arrayOffset());
206c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        } else {
207c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes            out.put(output, 0, data[OUTPUT_OFFSET]);
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
2099932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda        // release reference to output array, which may not be ours
2109932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda        output = null;
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
213866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    private void setPosition(ByteBuffer in) {
2142981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        in.position(in.position() + data[INPUT_OFFSET]);
2159932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda        // release reference to input array, which may not be ours
2169932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda        input = null;
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
219