12d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// © 2016 and later: Unicode, Inc. and others.
22d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License
37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/**
47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*******************************************************************************
57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* Copyright (C) 2006-2014, International Business Machines Corporation and
67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* others. All Rights Reserved.
77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*******************************************************************************
87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*/
97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.charset;
117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.nio.ByteBuffer;
137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.nio.CharBuffer;
147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.nio.IntBuffer;
157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.nio.charset.CoderResult;
167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/**
187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <h2> Callback API for CharsetICU API </h2>
192d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert *
202d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert *  CharsetCallback class defines some error behaviour functions called
217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *  by CharsetDecoderICU and CharsetEncoderICU. The class also provides
227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *  the facility by which clients can write their own callbacks.
237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *  These functions, although public, should NEVER be called directly.
252d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert *  They should be used as parameters to the onUmappableCharacter() and
267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *  onMalformedInput() methods, to set the behaviour of a converter
277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *  when it encounters UNMAPPED/INVALID sequences.
287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *  Currently the only way to set callbacks is by using CodingErrorAction.
297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *  In the future we will provide set methods on CharsetEncoder and CharsetDecoder
307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *  that will accept CharsetCallback fields.
317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6
337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class CharsetCallback {
367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * FROM_U, TO_U context options for sub callback
387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final String SUB_STOP_ON_ILLEGAL = "i";
407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//    /*
427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//     * FROM_U, TO_U context options for skip callback
437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//     */
447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//    private static final String SKIP_STOP_ON_ILLEGAL = "i";
457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//    /*
472d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert//     * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to ICU (%UXXXX)
487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//     */
497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//    private static final String ESCAPE_ICU  = null;
507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to JAVA (\\uXXXX)
537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final String ESCAPE_JAVA     =  "J";
557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to C (\\uXXXX \\UXXXXXXXX)
587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * TO_U_CALLBACK_ESCAPE option to escape the character value accoding to C (\\xXXXX)
597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final String ESCAPE_C        = "C";
617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to XML Decimal escape \htmlonly(&amp;#DDDD;)\endhtmlonly
647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * TO_U_CALLBACK_ESCAPE context option to escape the character value accoding to XML Decimal escape \htmlonly(&amp;#DDDD;)\endhtmlonly
657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final String ESCAPE_XML_DEC  = "D";
677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to XML Hex escape \htmlonly(&amp;#xXXXX;)\endhtmlonly
707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * TO_U_CALLBACK_ESCAPE context option to escape the character value according to XML Hex escape \htmlonly(&amp;#xXXXX;)\endhtmlonly
717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final String ESCAPE_XML_HEX  = "X";
737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to Unicode (U+XXXXX)
767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final String ESCAPE_UNICODE  = "U";
787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to Unicode (U+XXXXX)
817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final String ESCAPE_CSS2  = "S";
837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * IS_DEFAULT_IGNORABLE_CODE_POINT
867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * This is to check if a code point has the default ignorable unicode property.
877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * As such, this list needs to be updated if the ignorable code point list ever
887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * changes.
897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * To avoid dependency on other code, this list is hard coded here.
907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * When an ignorable code point is found and is unmappable, the default callbacks
917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * will ignore them.
927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * For a list of the default ignorable code points, use this link: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[%3ADI%3A]&g=
937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * This list should be sync with the one in ucnv_err.c
952d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert     *
967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static boolean IS_DEFAULT_IGNORABLE_CODE_POINT(int c) {
982d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        return ((c == 0x00AD) ||
992d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (c == 0x034F) ||
1002d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (c == 0x061C) ||
1012d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (c == 0x115F) ||
1022d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (c == 0x1160) ||
1032d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x17B4 <= c && c <= 0x17B5) ||
1042d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x180B <= c && c <= 0x180E) ||
1052d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x200B <= c && c <= 0x200F) ||
1062d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x202A <= c && c <= 0x202E) ||
1072d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (c == 0x2060) ||
1082d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x2066 <= c && c <= 0x2069) ||
1092d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x2061 <= c && c <= 0x2064) ||
1102d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x206A <= c && c <= 0x206F) ||
1112d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (c == 0x3164) ||
1122d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x0FE00 <= c && c <= 0x0FE0F) ||
1132d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (c == 0x0FEFF) ||
1142d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (c == 0x0FFA0) ||
1152d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x01BCA0  <= c && c <= 0x01BCA3) ||
1162d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x01D173 <= c && c <= 0x01D17A) ||
1172d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (c == 0x0E0001) ||
1182d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x0E0020 <= c && c <= 0x0E007F) ||
1192d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x0E0100 <= c && c <= 0x0E01EF) ||
1202d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (c == 0x2065) ||
1212d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x0FFF0 <= c && c <= 0x0FFF8) ||
1222d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (c == 0x0E0000) ||
1232d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x0E0002 <= c && c <= 0x0E001F) ||
1242d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                (0x0E0080 <= c && c <= 0x0E00FF) ||
1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                (0x0E01F0 <= c && c <= 0x0E0FFF)
1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                );
1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Decoder Callback interface
1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.6
1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public interface Decoder {
1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * This function is called when the bytes in the source cannot be handled,
1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * and this function is meant to handle or fix the error if possible.
1362d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert         *
1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * @return Result of decoding action. This returned object is set to an error
1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         *  if this function could not handle the conversion.
1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * @stable ICU 3.6
1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         */
1412d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        public CoderResult call(CharsetDecoderICU decoder, Object context,
1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                ByteBuffer source, CharBuffer target, IntBuffer offsets,
1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                char[] buffer, int length, CoderResult cr);
1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Encoder Callback interface
1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.6
1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public interface Encoder {
1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /**
1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * This function is called when the Unicode characters in the source cannot be handled,
1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * and this function is meant to handle or fix the error if possible.
1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * @return Result of decoding action. This returned object is set to an error
1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         *  if this function could not handle the conversion.
1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         * @stable ICU 3.6
1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert         */
1572d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        public CoderResult call(CharsetEncoderICU encoder, Object context,
1582d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                                CharBuffer source, ByteBuffer target, IntBuffer offsets,
1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                char[] buffer, int length, int cp, CoderResult cr);
1602d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert    }
1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Skip callback
1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.6
1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final Encoder FROM_U_CALLBACK_SKIP = new Encoder() {
1662d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        @Override
1672d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        public CoderResult call(CharsetEncoderICU encoder, Object context,
1682d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                CharBuffer source, ByteBuffer target, IntBuffer offsets,
1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                char[] buffer, int length, int cp, CoderResult cr){
1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if(context==null){
1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return CoderResult.UNDERFLOW;
1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }else if(((String)context).equals(SUB_STOP_ON_ILLEGAL)){
1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if(!cr.isUnmappable()){
1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return cr;
1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }else{
1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return CoderResult.UNDERFLOW;
1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return cr;
1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    };
1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Skip callback
1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.6
1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final Decoder TO_U_CALLBACK_SKIP = new Decoder() {
1872d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        @Override
1882d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        public CoderResult call(CharsetDecoderICU decoder, Object context,
1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ByteBuffer source, CharBuffer target, IntBuffer offsets,
1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                char[] buffer, int length, CoderResult cr){
1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if(context==null){
1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return CoderResult.UNDERFLOW;
1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }else if(((String)context).equals(SUB_STOP_ON_ILLEGAL)){
1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if(!cr.isUnmappable()){
1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return cr;
1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }else{
1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return CoderResult.UNDERFLOW;
1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return cr;
2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    };
2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Write substitute callback
2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.6
2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2072d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert    public static final Encoder FROM_U_CALLBACK_SUBSTITUTE = new Encoder(){
2082d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        @Override
2092d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        public CoderResult call(CharsetEncoderICU encoder, Object context,
2102d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                CharBuffer source, ByteBuffer target, IntBuffer offsets,
2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                char[] buffer, int length, int cp, CoderResult cr){
2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (cr.isUnmappable() && IS_DEFAULT_IGNORABLE_CODE_POINT(cp)) {
2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return CoderResult.UNDERFLOW;
2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }else if(context==null){
2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return encoder.cbFromUWriteSub(encoder, source, target, offsets);
2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }else if(((String)context).equals(SUB_STOP_ON_ILLEGAL)){
2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if(!cr.isUnmappable()){
2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return cr;
2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }else{
2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                   return encoder.cbFromUWriteSub(encoder, source, target, offsets);
2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return cr;
2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    };
2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char[] kSubstituteChar1 = new char[]{0x1A};
2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char[] kSubstituteChar = new char[] {0xFFFD};
2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Write substitute callback
2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.6
2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final Decoder TO_U_CALLBACK_SUBSTITUTE  = new Decoder() {
2332d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        @Override
2342d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        public CoderResult call(CharsetDecoderICU decoder, Object context,
2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ByteBuffer source, CharBuffer target, IntBuffer offsets,
2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                char[] buffer, int length, CoderResult cr){
2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            CharsetICU cs = (CharsetICU) decoder.charset();
2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            /* Use the specified replacement character if it is different than the default one. */
2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            boolean useReplacement = true;
2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            char [] replacementChar = decoder.replacement().toCharArray();
2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (replacementChar.length == 1 && (replacementChar[0] == kSubstituteChar1[0] || replacementChar[0] == kSubstituteChar[0])) {
2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                useReplacement = false;
2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2452d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert
2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            /* could optimize this case, just one uchar */
2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if(decoder.invalidCharLength == 1 && cs.subChar1 != 0) {
2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return CharsetDecoderICU.toUWriteUChars(decoder, useReplacement ? replacementChar : kSubstituteChar1, 0, useReplacement ? replacementChar.length : 1, target, offsets, source.position());
2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return CharsetDecoderICU.toUWriteUChars(decoder, useReplacement ? replacementChar : kSubstituteChar, 0, useReplacement ? replacementChar.length : 1, target, offsets, source.position());
2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    };
2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Stop callback
2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.6
2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final Encoder FROM_U_CALLBACK_STOP = new Encoder() {
2592d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        @Override
2602d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        public CoderResult call(CharsetEncoderICU encoder, Object context,
2612d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                CharBuffer source, ByteBuffer target, IntBuffer offsets,
2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                char[] buffer, int length, int cp, CoderResult cr){
2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (cr.isUnmappable() && IS_DEFAULT_IGNORABLE_CODE_POINT(cp)) {
2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return CoderResult.UNDERFLOW;
2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return cr;
2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    };
2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Stop callback
2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.6
2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final Decoder TO_U_CALLBACK_STOP = new Decoder() {
2742d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        @Override
2752d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        public CoderResult call(CharsetDecoderICU decoder, Object context,
2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ByteBuffer source, CharBuffer target, IntBuffer offsets,
2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                char[] buffer, int length, CoderResult cr){
2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return cr;
2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2802d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert    };
2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int VALUE_STRING_LENGTH = 32;
2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char UNICODE_PERCENT_SIGN_CODEPOINT    = 0x0025;
2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char UNICODE_U_CODEPOINT               = 0x0055;
2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char UNICODE_X_CODEPOINT               = 0x0058;
2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char UNICODE_RS_CODEPOINT              = 0x005C;
2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char UNICODE_U_LOW_CODEPOINT           = 0x0075;
2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char UNICODE_X_LOW_CODEPOINT           = 0x0078;
2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char UNICODE_AMP_CODEPOINT             = 0x0026;
2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char UNICODE_HASH_CODEPOINT            = 0x0023;
2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char UNICODE_SEMICOLON_CODEPOINT       = 0x003B;
2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char UNICODE_PLUS_CODEPOINT            = 0x002B;
2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char UNICODE_LEFT_CURLY_CODEPOINT      = 0x007B;
2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char UNICODE_RIGHT_CURLY_CODEPOINT     = 0x007D;
2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final char UNICODE_SPACE_CODEPOINT           = 0x0020;
2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Write escape callback
2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 4.0
2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final Encoder FROM_U_CALLBACK_ESCAPE = new Encoder() {
3002d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        @Override
3012d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        public CoderResult call(CharsetEncoderICU encoder, Object context,
3022d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert                CharBuffer source, ByteBuffer target, IntBuffer offsets,
3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                char[] buffer, int length, int cp, CoderResult cr){
3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            char[] valueString = new char[VALUE_STRING_LENGTH];
3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            int valueStringLength = 0;
3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            int i = 0;
3072d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert
3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (cr.isUnmappable() && IS_DEFAULT_IGNORABLE_CODE_POINT(cp)) {
3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return CoderResult.UNDERFLOW;
3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
3112d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert
3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (context == null || !(context instanceof String)) {
3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                while (i < length) {
3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_PERCENT_SIGN_CODEPOINT; /* adding % */
3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_U_CODEPOINT; /* adding U */
3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueStringLength += itou(valueString, valueStringLength, buffer[i++], 16, 4);
3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (((String)context).equals(ESCAPE_JAVA)) {
3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    while (i < length) {
3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueString[valueStringLength++] = UNICODE_RS_CODEPOINT;    /* adding \ */
3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueString[valueStringLength++] = UNICODE_U_LOW_CODEPOINT; /* adding u */
3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueStringLength += itou(valueString, valueStringLength, buffer[i++], 16, 4);
3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else if (((String)context).equals(ESCAPE_C)) {
3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_RS_CODEPOINT;    /* adding \ */
3272d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert
3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (length == 2) {
3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueString[valueStringLength++] = UNICODE_U_CODEPOINT; /* adding U */
3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueStringLength = itou(valueString, valueStringLength, cp, 16, 8);
3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    } else {
3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueString[valueStringLength++] = UNICODE_U_LOW_CODEPOINT; /* adding u */
3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueStringLength += itou(valueString, valueStringLength, buffer[0], 16, 4);
3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else if (((String)context).equals(ESCAPE_XML_DEC)) {
3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_AMP_CODEPOINT;   /* adding & */
3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_HASH_CODEPOINT;  /* adding # */
3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (length == 2) {
3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueStringLength += itou(valueString, valueStringLength, cp, 10, 0);
3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    } else {
3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueStringLength += itou(valueString, valueStringLength, buffer[0], 10, 0);
3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_SEMICOLON_CODEPOINT; /* adding ; */
3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else if (((String)context).equals(ESCAPE_XML_HEX)) {
3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_AMP_CODEPOINT;   /* adding & */
3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_HASH_CODEPOINT;  /* adding # */
3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_X_LOW_CODEPOINT; /* adding x */
3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (length == 2) {
3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueStringLength += itou(valueString, valueStringLength, cp, 16, 0);
3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    } else {
3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueStringLength += itou(valueString, valueStringLength, buffer[0], 16, 0);
3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_SEMICOLON_CODEPOINT; /* adding ; */
3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else if (((String)context).equals(ESCAPE_UNICODE)) {
3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_LEFT_CURLY_CODEPOINT;    /* adding { */
3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_U_CODEPOINT;             /* adding U */
3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_PLUS_CODEPOINT;          /* adding + */
3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (length == 2) {
3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueStringLength += itou(valueString, valueStringLength,cp, 16, 4);
3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    } else {
3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueStringLength += itou(valueString, valueStringLength, buffer[0], 16, 4);
3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_RIGHT_CURLY_CODEPOINT;   /* adding } */
3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else if (((String)context).equals(ESCAPE_CSS2)) {
3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_RS_CODEPOINT;    /* adding \ */
3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueStringLength += itou(valueString, valueStringLength, cp, 16, 0);
3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    /* Always add space character, because the next character might be whitespace,
3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                       which would erroneously be considered the termination of the escape sequence. */
3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueString[valueStringLength++] = UNICODE_SPACE_CODEPOINT;
3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    while (i < length) {
3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueString[valueStringLength++] = UNICODE_PERCENT_SIGN_CODEPOINT;  /* adding % */
3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueString[valueStringLength++] = UNICODE_U_CODEPOINT;             /* adding U */
3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueStringLength += itou(valueString, valueStringLength, buffer[i++], 16, 4);
3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return encoder.cbFromUWriteUChars(encoder, CharBuffer.wrap(valueString, 0, valueStringLength), target, offsets);
3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    };
3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Write escape callback
3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 4.0
3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final Decoder TO_U_CALLBACK_ESCAPE = new Decoder() {
3862d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        @Override
3872d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert        public CoderResult call(CharsetDecoderICU decoder, Object context,
3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ByteBuffer source, CharBuffer target, IntBuffer offsets,
3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                char[] buffer, int length, CoderResult cr){
3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            char[] uniValueString = new char[VALUE_STRING_LENGTH];
3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            int valueStringLength = 0;
3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            int i = 0;
3932d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert
3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (context == null || !(context instanceof String)) {
3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                while (i < length) {
3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    uniValueString[valueStringLength++] = UNICODE_PERCENT_SIGN_CODEPOINT;   /* adding % */
3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    uniValueString[valueStringLength++] = UNICODE_X_CODEPOINT;              /* adding U */
3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    valueStringLength += itou(uniValueString, valueStringLength, buffer[i++] & UConverterConstants.UNSIGNED_BYTE_MASK, 16, 2);
3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (((String)context).equals(ESCAPE_XML_DEC)) {
4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    while (i < length) {
4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        uniValueString[valueStringLength++] = UNICODE_AMP_CODEPOINT;    /* adding & */
4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        uniValueString[valueStringLength++] = UNICODE_HASH_CODEPOINT;   /* adding # */
4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueStringLength += itou(uniValueString, valueStringLength, buffer[i++] & UConverterConstants.UNSIGNED_BYTE_MASK, 10, 0);
4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        uniValueString[valueStringLength++] = UNICODE_SEMICOLON_CODEPOINT;  /* adding ; */
4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else if (((String)context).equals(ESCAPE_XML_HEX)) {
4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    while (i < length) {
4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        uniValueString[valueStringLength++] = UNICODE_AMP_CODEPOINT;    /* adding & */
4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        uniValueString[valueStringLength++] = UNICODE_HASH_CODEPOINT;   /* adding # */
4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        uniValueString[valueStringLength++] = UNICODE_X_LOW_CODEPOINT;  /* adding x */
4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueStringLength += itou(uniValueString, valueStringLength, buffer[i++] & UConverterConstants.UNSIGNED_BYTE_MASK, 16, 0);
4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        uniValueString[valueStringLength++] = UNICODE_SEMICOLON_CODEPOINT;  /* adding ; */
4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else if (((String)context).equals(ESCAPE_C)) {
4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    while (i < length) {
4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        uniValueString[valueStringLength++] = UNICODE_RS_CODEPOINT;         /* adding \ */
4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        uniValueString[valueStringLength++] = UNICODE_X_LOW_CODEPOINT;      /* adding x */
4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueStringLength += itou(uniValueString, valueStringLength, buffer[i++] & UConverterConstants.UNSIGNED_BYTE_MASK, 16, 2);
4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    while (i < length) {
4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        uniValueString[valueStringLength++] = UNICODE_PERCENT_SIGN_CODEPOINT;   /* adding % */
4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        uniValueString[valueStringLength++] = UNICODE_X_CODEPOINT;              /* adding X */
4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        itou(uniValueString, valueStringLength, buffer[i++] & UConverterConstants.UNSIGNED_BYTE_MASK, 16, 2);
4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        valueStringLength += 2;
4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
4312d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert
4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            cr = CharsetDecoderICU.toUWriteUChars(decoder, uniValueString, 0, valueStringLength, target, offsets, 0);
4332d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert
4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return cr;
4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
4362d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert    };
4377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /***
4387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Java port of uprv_itou() in ICU4C used by TO_U_CALLBACK_ESCAPE and FROM_U_CALLBACK_ESCAPE.
4397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Fills in a char string with the radix-based representation of a number padded with zeroes
4407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * to minwidth.
4417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
4427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int itou(char[] buffer, int sourceIndex, int i, int radix, int minwidth) {
4437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int length = 0;
4447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int digit;
4457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int j;
4467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        char temp;
4472d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert
4487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        do {
4497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            digit = i % radix;
4507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            buffer[sourceIndex + length++] = (char)(digit <= 9 ? (0x0030+digit) : (0x0030+digit+7));
4517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            i = i/radix;
4527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } while (i != 0 && (sourceIndex + length) < buffer.length);
4532d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert
4547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        while (length < minwidth) {
4557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            buffer[sourceIndex + length++] = (char)0x0030; /* zero padding */
4567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
4577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /* reverses the string */
4587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (j = 0; j < (length / 2); j++) {
4597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            temp = buffer[(sourceIndex + length - 1) - j];
4607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            buffer[(sourceIndex + length-1) -j] = buffer[sourceIndex + j];
4617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            buffer[sourceIndex + j] = temp;
4627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
4632d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert
4647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return length;
4657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
4687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * No need to create an instance
4697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
4707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private CharsetCallback() {
4717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert}
473