CharsetEncoderICU.java revision f15b280ac1c2e32f7becdb314440c2999dc8d204
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; 43f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath private static final int INVALID_CHAR_COUNT = 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; 121f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath data[INVALID_CHAR_COUNT] = 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); 138f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath data[INVALID_CHAR_COUNT] = 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) { 145f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath if (data[INVALID_CHAR_COUNT] > 0) { 146f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath return CoderResult.malformedForLength(data[INVALID_CHAR_COUNT]); 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); 164f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath data[INVALID_CHAR_COUNT] = 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) { 172f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath return CoderResult.unmappableForLength(data[INVALID_CHAR_COUNT]); 1735ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes } else if (error == ICU.U_ILLEGAL_CHAR_FOUND) { 174f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath return CoderResult.malformedForLength(data[INVALID_CHAR_COUNT]); 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 187e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom @Override protected void finalize() throws Throwable { 188e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom try { 189e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom NativeConverter.closeConverter(converterHandle); 190e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom converterHandle=0; 191e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom } finally { 192e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom super.finalize(); 193e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom } 194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 196866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes private int getArray(ByteBuffer out) { 197866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes if (out.hasArray()) { 198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project output = out.array(); 199b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes outEnd = out.arrayOffset() + out.limit(); 200b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes return out.arrayOffset() + out.position(); 201866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes } else { 202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project outEnd = out.remaining(); 2032981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes if (allocatedOutput == null || outEnd > allocatedOutput.length) { 2049932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda allocatedOutput = new byte[outEnd]; 205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 20633604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes // The array's start position is 0 2079932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda output = allocatedOutput; 208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return 0; 209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 212866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes private int getArray(CharBuffer in) { 213866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes if (in.hasArray()) { 214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project input = in.array(); 215b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes inEnd = in.arrayOffset() + in.limit(); 21633604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes return in.arrayOffset() + in.position(); 217866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes } else { 218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project inEnd = in.remaining(); 21933604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes if (allocatedInput == null || inEnd > allocatedInput.length) { 2209932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda allocatedInput = new char[inEnd]; 221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 22233604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes // Copy the input buffer into the allocated array. 223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int pos = in.position(); 22433604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes in.get(allocatedInput, 0, inEnd); 225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project in.position(pos); 22633604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes // The array's start position is 0 22733604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes input = allocatedInput; 22833604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes return 0; 229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 231f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 23233604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes private void setPosition(ByteBuffer out) { 233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (out.hasArray()) { 234b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes out.position(out.position() + data[OUTPUT_OFFSET] - out.arrayOffset()); 235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project out.put(output, 0, data[OUTPUT_OFFSET]); 237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 2389932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda // release reference to output array, which may not be ours 2399932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda output = null; 240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 24233604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes private void setPosition(CharBuffer in) { 243f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath in.position(in.position() + data[INPUT_OFFSET] - data[INVALID_CHAR_COUNT]); 2449932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda // release reference to input array, which may not be ours 2459932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda input = null; 246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 248