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 17e31b37859051d3902e06e4ba384995df7188917fHans Boehmimport dalvik.annotation.optimization.ReachabilitySensitive; 18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.ByteBuffer; 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.CharBuffer; 207d52d787302b862019da41aa753646d88d43fd61Elliott Hughesimport java.util.HashMap; 217d52d787302b862019da41aa753646d88d43fd61Elliott Hughesimport java.util.Map; 225ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughesimport libcore.icu.ICU; 233664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughesimport libcore.icu.NativeConverter; 2426ce8fbd8fe488cc969b08f64c56525662763dc4Jesse Wilsonimport libcore.util.EmptyArray; 25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 264fd8ac297725190c6d81e9538b1faf7cfb0f5bb8Elliott Hughesfinal class CharsetEncoderICU extends CharsetEncoder { 277d52d787302b862019da41aa753646d88d43fd61Elliott Hughes private static final Map<String, byte[]> DEFAULT_REPLACEMENTS = new HashMap<String, byte[]>(); 287d52d787302b862019da41aa753646d88d43fd61Elliott Hughes static { 2957a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes // ICU has different default replacements to the RI in some cases. There are many 3057a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes // additional cases, but this covers all the charsets that Java guarantees will be 3157a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes // available, which is where compatibility seems most important. (The RI even uses 3257a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes // the byte corresponding to '?' in ASCII as the replacement byte for charsets where that 3357a151cc43ef3dfc1040fad5581836c66c8e53f3Elliott Hughes // byte corresponds to an entirely different character.) 34d6db7651bf7868ff780d284eb1bfd6ad860ddc1fElliott Hughes // It's odd that UTF-8 doesn't use U+FFFD, given that (unlike ISO-8859-1 and US-ASCII) it 35d6db7651bf7868ff780d284eb1bfd6ad860ddc1fElliott Hughes // can represent it, but this is what the RI does... 367d52d787302b862019da41aa753646d88d43fd61Elliott Hughes byte[] questionMark = new byte[] { (byte) '?' }; 377d52d787302b862019da41aa753646d88d43fd61Elliott Hughes DEFAULT_REPLACEMENTS.put("UTF-8", questionMark); 387d52d787302b862019da41aa753646d88d43fd61Elliott Hughes DEFAULT_REPLACEMENTS.put("ISO-8859-1", questionMark); 397d52d787302b862019da41aa753646d88d43fd61Elliott Hughes DEFAULT_REPLACEMENTS.put("US-ASCII", questionMark); 407d52d787302b862019da41aa753646d88d43fd61Elliott Hughes } 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 42c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes private static final int INPUT_OFFSET = 0; 43c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes private static final int OUTPUT_OFFSET = 1; 44f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath private static final int INVALID_CHAR_COUNT = 2; 45c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes /* 46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * data[INPUT_OFFSET] = on input contains the start of input and on output the number of input chars consumed 47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * data[OUTPUT_OFFSET] = on input contains the start of output and on output the number of output bytes written 48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * data[INVALID_CHARS] = number of invalid chars 49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 5033604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes private int[] data = new int[3]; 512981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes 52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /* handle to the ICU converter that is opened */ 53e31b37859051d3902e06e4ba384995df7188917fHans Boehm @ReachabilitySensitive 541bdc6bc1c72b033ed860360e69fc9f1f1121579bNarayan Kamath private final long converterHandle; 55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private char[] input = null; 57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private byte[] output = null; 58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 599932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda private char[] allocatedInput = null; 609932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda private byte[] allocatedOutput = null; 619932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda 62866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes // These instance variables are always assigned in the methods before being used. This class 63866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes // is inherently thread-unsafe so we don't have to worry about synchronization. 64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private int inEnd; 65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private int outEnd; 66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 677d52d787302b862019da41aa753646d88d43fd61Elliott Hughes public static CharsetEncoderICU newInstance(Charset cs, String icuCanonicalName) { 687d52d787302b862019da41aa753646d88d43fd61Elliott Hughes // This complexity is necessary to ensure that even if the constructor, superclass 697d52d787302b862019da41aa753646d88d43fd61Elliott Hughes // constructor, or call to updateCallback throw, we still free the native peer. 707d52d787302b862019da41aa753646d88d43fd61Elliott Hughes long address = 0; 7159b140db4c4bd7617792256cd5d52713409137bcHans Boehm CharsetEncoderICU result; 727d52d787302b862019da41aa753646d88d43fd61Elliott Hughes try { 737d52d787302b862019da41aa753646d88d43fd61Elliott Hughes address = NativeConverter.openConverter(icuCanonicalName); 747d52d787302b862019da41aa753646d88d43fd61Elliott Hughes float averageBytesPerChar = NativeConverter.getAveBytesPerChar(address); 757d52d787302b862019da41aa753646d88d43fd61Elliott Hughes float maxBytesPerChar = NativeConverter.getMaxBytesPerChar(address); 767d52d787302b862019da41aa753646d88d43fd61Elliott Hughes byte[] replacement = makeReplacement(icuCanonicalName, address); 7759b140db4c4bd7617792256cd5d52713409137bcHans Boehm result = new CharsetEncoderICU(cs, averageBytesPerChar, maxBytesPerChar, replacement, address); 7859b140db4c4bd7617792256cd5d52713409137bcHans Boehm } catch (Throwable t) { 797d52d787302b862019da41aa753646d88d43fd61Elliott Hughes if (address != 0) { 807d52d787302b862019da41aa753646d88d43fd61Elliott Hughes NativeConverter.closeConverter(address); 817d52d787302b862019da41aa753646d88d43fd61Elliott Hughes } 8259b140db4c4bd7617792256cd5d52713409137bcHans Boehm throw t; 837d52d787302b862019da41aa753646d88d43fd61Elliott Hughes } 8459b140db4c4bd7617792256cd5d52713409137bcHans Boehm // An exception in registerConverter() will deallocate address: 8559b140db4c4bd7617792256cd5d52713409137bcHans Boehm NativeConverter.registerConverter(result, address); 8659b140db4c4bd7617792256cd5d52713409137bcHans Boehm result.updateCallback(); 8759b140db4c4bd7617792256cd5d52713409137bcHans Boehm return result; 887d52d787302b862019da41aa753646d88d43fd61Elliott Hughes } 897d52d787302b862019da41aa753646d88d43fd61Elliott Hughes 907d52d787302b862019da41aa753646d88d43fd61Elliott Hughes private static byte[] makeReplacement(String icuCanonicalName, long address) { 917d52d787302b862019da41aa753646d88d43fd61Elliott Hughes // We have our own map of RI-compatible default replacements (where ICU disagrees)... 927d52d787302b862019da41aa753646d88d43fd61Elliott Hughes byte[] replacement = DEFAULT_REPLACEMENTS.get(icuCanonicalName); 937d52d787302b862019da41aa753646d88d43fd61Elliott Hughes if (replacement != null) { 947d52d787302b862019da41aa753646d88d43fd61Elliott Hughes return replacement.clone(); 957d52d787302b862019da41aa753646d88d43fd61Elliott Hughes } 967d52d787302b862019da41aa753646d88d43fd61Elliott Hughes // ...but fall back to asking ICU. 977d52d787302b862019da41aa753646d88d43fd61Elliott Hughes return NativeConverter.getSubstitutionBytes(address); 987d52d787302b862019da41aa753646d88d43fd61Elliott Hughes } 997d52d787302b862019da41aa753646d88d43fd61Elliott Hughes 1007d52d787302b862019da41aa753646d88d43fd61Elliott Hughes private CharsetEncoderICU(Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement, long address) { 1013664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes super(cs, averageBytesPerChar, maxBytesPerChar, replacement, true); 1023664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes // Our native peer needs to know what just happened... 1037d52d787302b862019da41aa753646d88d43fd61Elliott Hughes this.converterHandle = address; 104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 10633604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes @Override protected void implReplaceWith(byte[] newReplacement) { 1073664d8839f0ba794f428119ee7f7304a66861da5Elliott Hughes updateCallback(); 108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 11033604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes @Override protected void implOnMalformedInput(CodingErrorAction newAction) { 111cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes updateCallback(); 112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 11433604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes @Override protected void implOnUnmappableCharacter(CodingErrorAction newAction) { 115cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes updateCallback(); 116cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes } 117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 118cf6c3a752da274cc5025191d3bcd62e6222f4a4cElliott Hughes private void updateCallback() { 1195ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes NativeConverter.setCallbackEncode(converterHandle, this); 120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 12233604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes @Override protected void implReset() { 12333604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes NativeConverter.resetCharToByte(converterHandle); 12433604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes data[INPUT_OFFSET] = 0; 12533604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes data[OUTPUT_OFFSET] = 0; 126f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath data[INVALID_CHAR_COUNT] = 0; 1272981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes output = null; 1282981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes input = null; 1292981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes allocatedInput = null; 1302981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes allocatedOutput = null; 1312981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes inEnd = 0; 1322981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes outEnd = 0; 13333604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes } 13433604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes 13533604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes @Override protected CoderResult implFlush(ByteBuffer out) { 136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 13733604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes // ICU needs to see an empty input. 13833604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes input = EmptyArray.CHAR; 139dbf863488607fbb16a3d28c09f772d9581bd64adElliott Hughes inEnd = 0; 14033604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes data[INPUT_OFFSET] = 0; 14133604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes 142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project data[OUTPUT_OFFSET] = getArray(out); 143f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath data[INVALID_CHAR_COUNT] = 0; // Make sure we don't see earlier errors. 144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1455ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes int error = NativeConverter.encode(converterHandle, input, inEnd, output, outEnd, data, true); 1465ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes if (ICU.U_FAILURE(error)) { 1475ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes if (error == ICU.U_BUFFER_OVERFLOW_ERROR) { 148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return CoderResult.OVERFLOW; 1495ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes } else if (error == ICU.U_TRUNCATED_CHAR_FOUND) { 150f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath if (data[INVALID_CHAR_COUNT] > 0) { 151f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath return CoderResult.malformedForLength(data[INVALID_CHAR_COUNT]); 152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return CoderResult.UNDERFLOW; 156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } finally { 157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project setPosition(out); 158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project implReset(); 159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 16233604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes @Override protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { 163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (!in.hasRemaining()) { 164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return CoderResult.UNDERFLOW; 165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project data[INPUT_OFFSET] = getArray(in); 168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project data[OUTPUT_OFFSET]= getArray(out); 169f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath data[INVALID_CHAR_COUNT] = 0; // Make sure we don't see earlier errors. 170f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 1725ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes int error = NativeConverter.encode(converterHandle, input, inEnd, output, outEnd, data, false); 1735ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes if (ICU.U_FAILURE(error)) { 1745ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes if (error == ICU.U_BUFFER_OVERFLOW_ERROR) { 175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return CoderResult.OVERFLOW; 1765ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes } else if (error == ICU.U_INVALID_CHAR_FOUND) { 177f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath return CoderResult.unmappableForLength(data[INVALID_CHAR_COUNT]); 1785ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes } else if (error == ICU.U_ILLEGAL_CHAR_FOUND) { 179f15b280ac1c2e32f7becdb314440c2999dc8d204Narayan Kamath return CoderResult.malformedForLength(data[INVALID_CHAR_COUNT]); 18033604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes } else { 1815ec69b20ab9b3e2dcbe225d548168b09afbbbac2Elliott Hughes throw new AssertionError(error); 182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1842981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes // Decoding succeeded: give us more data. 185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return CoderResult.UNDERFLOW; 186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } finally { 187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project setPosition(in); 188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project setPosition(out); 189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 192866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes private int getArray(ByteBuffer out) { 193866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes if (out.hasArray()) { 194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project output = out.array(); 195b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes outEnd = out.arrayOffset() + out.limit(); 196b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes return out.arrayOffset() + out.position(); 197866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes } else { 198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project outEnd = out.remaining(); 1992981b5e8cf7c19dfd85b2088b18b7a6146825317Elliott Hughes if (allocatedOutput == null || outEnd > allocatedOutput.length) { 2009932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda allocatedOutput = new byte[outEnd]; 201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 20233604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes // The array's start position is 0 2039932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda output = allocatedOutput; 204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return 0; 205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 208866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes private int getArray(CharBuffer in) { 209866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes if (in.hasArray()) { 210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project input = in.array(); 211b7bfb47e9720ecc6e10f43878f27e40542a9c800Elliott Hughes inEnd = in.arrayOffset() + in.limit(); 21233604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes return in.arrayOffset() + in.position(); 213866e7ae17a3da81a02b0b144e0c9c2b3196d293aElliott Hughes } else { 214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project inEnd = in.remaining(); 21533604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes if (allocatedInput == null || inEnd > allocatedInput.length) { 2169932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda allocatedInput = new char[inEnd]; 217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 21833604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes // Copy the input buffer into the allocated array. 219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int pos = in.position(); 22033604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes in.get(allocatedInput, 0, inEnd); 221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project in.position(pos); 22233604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes // The array's start position is 0 22333604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes input = allocatedInput; 22433604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes return 0; 225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 227f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 22833604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes private void setPosition(ByteBuffer out) { 229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (out.hasArray()) { 2304e4b93ffe988b0a597835d852489573b57e0f3feNarayan Kamath out.position(data[OUTPUT_OFFSET] - out.arrayOffset()); 231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project out.put(output, 0, data[OUTPUT_OFFSET]); 233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 2349932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda // release reference to output array, which may not be ours 2359932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda output = null; 236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 23833604713c5c70f9e6cad61dee6eb628db666bb22Elliott Hughes private void setPosition(CharBuffer in) { 23991bb19d2ef9822cfb50fd1191cdb3ee06e2939b9Narayan Kamath int position = in.position() + data[INPUT_OFFSET] - data[INVALID_CHAR_COUNT]; 24091bb19d2ef9822cfb50fd1191cdb3ee06e2939b9Narayan Kamath if (position < 0) { 24191bb19d2ef9822cfb50fd1191cdb3ee06e2939b9Narayan Kamath // The calculated position might be negative if we encountered an 24291bb19d2ef9822cfb50fd1191cdb3ee06e2939b9Narayan Kamath // invalid char that spanned input buffers. We adjust it to 0 in this case. 24391bb19d2ef9822cfb50fd1191cdb3ee06e2939b9Narayan Kamath // 24491bb19d2ef9822cfb50fd1191cdb3ee06e2939b9Narayan Kamath // NOTE: The API doesn't allow us to adjust the position of the previous 24591bb19d2ef9822cfb50fd1191cdb3ee06e2939b9Narayan Kamath // input buffer. (Doing that wouldn't serve any useful purpose anyway.) 24691bb19d2ef9822cfb50fd1191cdb3ee06e2939b9Narayan Kamath position = 0; 24791bb19d2ef9822cfb50fd1191cdb3ee06e2939b9Narayan Kamath } 24891bb19d2ef9822cfb50fd1191cdb3ee06e2939b9Narayan Kamath 24991bb19d2ef9822cfb50fd1191cdb3ee06e2939b9Narayan Kamath in.position(position); 2509932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda // release reference to input array, which may not be ours 2519932735d0306721523082f77b0a9ba4aa4db8cdbMihai Preda input = null; 252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 254