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;
28bd024cc687470a008999d96fd3af4a1261413d55Narayan Kamath    private static final int INVALID_BYTE_COUNT = 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
32bd024cc687470a008999d96fd3af4a1261413d55Narayan Kamath     * data[INVALID_BYTE_COUNT]  = number of invalid bytes
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
34bd024cc687470a008999d96fd3af4a1261413d55Narayan Kamath    private final 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;
711bdc6bc1c72b033ed860360e69fc9f1f1121579bNarayan Kamath        NativeConverter.registerConverter(this, converterHandle);
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
73f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
742981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes    @Override protected void implReplaceWith(String newReplacement) {
7537871fb106b08055ad56d7f04d4faccdd163e1afElliott Hughes        updateCallback();
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     }
77f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
782981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes    @Override protected final void implOnMalformedInput(CodingErrorAction newAction) {
79cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes        updateCallback();
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
81f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
822981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes    @Override protected final void implOnUnmappableCharacter(CodingErrorAction newAction) {
83cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes        updateCallback();
84cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes    }
85cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes
86cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes    private void updateCallback() {
875ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes        NativeConverter.setCallbackDecode(converterHandle, this);
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
89f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
902981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes    @Override protected void implReset() {
912981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        NativeConverter.resetByteToChar(converterHandle);
922981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        data[INPUT_OFFSET] = 0;
932981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        data[OUTPUT_OFFSET] = 0;
94bd024cc687470a008999d96fd3af4a1261413d55Narayan Kamath        data[INVALID_BYTE_COUNT] = 0;
952981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        output = null;
962981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        input = null;
972981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        allocatedInput = null;
982981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        allocatedOutput = null;
992981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        inEnd = 0;
1002981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        outEnd = 0;
1012981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes    }
1022981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes
103dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes    @Override protected final CoderResult implFlush(CharBuffer out) {
104c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        try {
105dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes            // ICU needs to see an empty input.
106dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes            input = EmptyArray.BYTE;
107dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes            inEnd = 0;
108dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes            data[INPUT_OFFSET] = 0;
109dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes
110c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes            data[OUTPUT_OFFSET] = getArray(out);
111bd024cc687470a008999d96fd3af4a1261413d55Narayan Kamath            data[INVALID_BYTE_COUNT] = 0; // Make sure we don't see earlier errors.
112dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes
1135ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes            int error = NativeConverter.decode(converterHandle, input, inEnd, output, outEnd, data, true);
1145ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes            if (ICU.U_FAILURE(error)) {
1155ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return CoderResult.OVERFLOW;
1175ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                } else if (error == ICU.U_TRUNCATED_CHAR_FOUND) {
118bd024cc687470a008999d96fd3af4a1261413d55Narayan Kamath                    if (data[INVALID_BYTE_COUNT] > 0) {
119bd024cc687470a008999d96fd3af4a1261413d55Narayan Kamath                        return CoderResult.malformedForLength(data[INVALID_BYTE_COUNT]);
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return CoderResult.UNDERFLOW;
124c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes       } finally {
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setPosition(out);
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            implReset();
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project       }
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
129f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
130dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes    @Override protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
131dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes        if (!in.hasRemaining()) {
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return CoderResult.UNDERFLOW;
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        data[INPUT_OFFSET] = getArray(in);
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        data[OUTPUT_OFFSET]= getArray(out);
137f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
1382981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        try {
1395ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes            int error = NativeConverter.decode(converterHandle, input, inEnd, output, outEnd, data, false);
1405ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes            if (ICU.U_FAILURE(error)) {
1415ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
1425ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                    return CoderResult.OVERFLOW;
1435ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                } else if (error == ICU.U_INVALID_CHAR_FOUND) {
144bd024cc687470a008999d96fd3af4a1261413d55Narayan Kamath                    return CoderResult.unmappableForLength(data[INVALID_BYTE_COUNT]);
1455ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                } else if (error == ICU.U_ILLEGAL_CHAR_FOUND) {
146bd024cc687470a008999d96fd3af4a1261413d55Narayan Kamath                    return CoderResult.malformedForLength(data[INVALID_BYTE_COUNT]);
1475ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                } else {
1485ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                    throw new AssertionError(error);
1495ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes                }
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
151c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes            // Decoding succeeded: give us more data.
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return CoderResult.UNDERFLOW;
153c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        } finally {
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setPosition(in);
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            setPosition(out);
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
158f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
159f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
160866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    private int getArray(CharBuffer out) {
161c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        if (out.hasArray()) {
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            output = out.array();
163b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes            outEnd = out.arrayOffset() + out.limit();
164b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes            return out.arrayOffset() + out.position();
165c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        } else {
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            outEnd = out.remaining();
1672981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            if (allocatedOutput == null || outEnd > allocatedOutput.length) {
1689932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda                allocatedOutput = new char[outEnd];
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1702981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            // The array's start position is 0.
1719932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda            output = allocatedOutput;
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
175c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes
176866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    private  int getArray(ByteBuffer in) {
177c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        if (in.hasArray()) {
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            input = in.array();
179b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes            inEnd = in.arrayOffset() + in.limit();
1802981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            return in.arrayOffset() + in.position();
181c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        } else {
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            inEnd = in.remaining();
1832981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            if (allocatedInput == null || inEnd > allocatedInput.length) {
1849932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda                allocatedInput = new byte[inEnd];
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1862981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            // Copy the input buffer into the allocated array.
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int pos = in.position();
1882981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            in.get(allocatedInput, 0, inEnd);
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            in.position(pos);
1902981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            // The array's start position is 0.
1912981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            input = allocatedInput;
1922981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes            return 0;
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
195c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes
196866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    private void setPosition(CharBuffer out) {
197c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        if (out.hasArray()) {
198654e8191641085aa6bff6df6aaef9a8cb0c03ec1Narayan Kamath            out.position(out.position() + data[OUTPUT_OFFSET]);
199c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        } else {
200c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes            out.put(output, 0, data[OUTPUT_OFFSET]);
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
2029932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda        // release reference to output array, which may not be ours
2039932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda        output = null;
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
206866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes    private void setPosition(ByteBuffer in) {
2072981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes        in.position(in.position() + data[INPUT_OFFSET]);
2089932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda        // release reference to input array, which may not be ours
2099932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda        input = null;
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
212