1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  this work for additional information regarding copyright ownership.
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  the License.  You may obtain a copy of the License at
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  See the License for the specific language governing permissions and
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  limitations under the License.
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage java.net;
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.ByteArrayOutputStream;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.UnsupportedEncodingException;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.apache.harmony.luni.util.Msg;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This class is used to encode a string using the format required by {@code
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * application/x-www-form-urlencoded} MIME content type. It contains helper
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * methods used by the URI class, and performs encoding and decoding in a
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * slightly different way than {@code URLEncoder} and {@code URLDecoder}.
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectclass URIEncoderDecoder {
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    static final String digits = "0123456789ABCDEF"; //$NON-NLS-1$
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    static final String encoding = "UTF8"; //$NON-NLS-1$
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Validate a string by checking if it contains any characters other than:
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * 1. letters ('a'..'z', 'A'..'Z') 2. numbers ('0'..'9') 3. characters in
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the legalset parameter 4. others (unicode characters that are not in
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * US-ASCII set, and are not ISO Control or are not ISO Space characters)
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <p>
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * called from {@code URI.Helper.parseURI()} to validate each component
443819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param s
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            {@code java.lang.String} the string to be validated
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param legal
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            {@code java.lang.String} the characters allowed in the String
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            s
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    static void validate(String s, String legal) throws URISyntaxException {
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < s.length();) {
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            char ch = s.charAt(i);
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (ch == '%') {
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                do {
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (i + 2 >= s.length()) {
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new URISyntaxException(s, Msg.getString("K0313"), //$NON-NLS-1$
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                i);
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int d1 = Character.digit(s.charAt(i + 1), 16);
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int d2 = Character.digit(s.charAt(i + 2), 16);
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (d1 == -1 || d2 == -1) {
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new URISyntaxException(s, Msg.getString("K0314", //$NON-NLS-1$
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                s.substring(i, i + 3)), i);
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    i += 3;
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } while (i < s.length() && s.charAt(i) == '%');
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                continue;
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    || (ch >= '0' && ch <= '9') || legal.indexOf(ch) > -1 || (ch > 127
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    && !Character.isSpaceChar(ch) && !Character
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    .isISOControl(ch)))) {
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw new URISyntaxException(s, Msg.getString("K00c1"), i); //$NON-NLS-1$
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            i++;
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    static void validateSimple(String s, String legal)
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throws URISyntaxException {
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < s.length();) {
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            char ch = s.charAt(i);
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    || (ch >= '0' && ch <= '9') || legal.indexOf(ch) > -1)) {
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw new URISyntaxException(s, Msg.getString("K00c1"), i); //$NON-NLS-1$
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            i++;
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * All characters except letters ('a'..'z', 'A'..'Z') and numbers ('0'..'9')
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * and legal characters are converted into their hexidecimal value prepended
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * by '%'.
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <p>
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * For example: '#' -> %23
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Other characters, which are unicode chars that are not US-ASCII, and are
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * not ISO Control or are not ISO Space chars, are preserved.
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <p>
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Called from {@code URI.quoteComponent()} (for multiple argument
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * constructors)
1053819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param s
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            java.lang.String the string to be converted
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param legal
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            java.lang.String the characters allowed to be preserved in the
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            string s
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return java.lang.String the converted string
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    static String quoteIllegal(String s, String legal)
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throws UnsupportedEncodingException {
11501021fcb0c9026e81ac2c262caf5e2ec830a7025Jesse Wilson        StringBuilder buf = new StringBuilder();
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < s.length(); i++) {
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            char ch = s.charAt(i);
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((ch >= 'a' && ch <= 'z')
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    || (ch >= 'A' && ch <= 'Z')
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    || (ch >= '0' && ch <= '9')
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    || legal.indexOf(ch) > -1
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    || (ch > 127 && !Character.isSpaceChar(ch) && !Character
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            .isISOControl(ch))) {
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                buf.append(ch);
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                byte[] bytes = new String(new char[] { ch }).getBytes(encoding);
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (int j = 0; j < bytes.length; j++) {
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    buf.append('%');
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    buf.append(digits.charAt((bytes[j] & 0xf0) >> 4));
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    buf.append(digits.charAt(bytes[j] & 0xf));
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return buf.toString();
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Other characters, which are Unicode chars that are not US-ASCII, and are
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * not ISO Control or are not ISO Space chars are not preserved. They are
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * converted into their hexidecimal value prepended by '%'.
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <p>
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * For example: Euro currency symbol -> "%E2%82%AC".
1433819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     * <p>
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Called from URI.toASCIIString()
1453819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param s
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            java.lang.String the string to be converted
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return java.lang.String the converted string
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    static String encodeOthers(String s) throws UnsupportedEncodingException {
15101021fcb0c9026e81ac2c262caf5e2ec830a7025Jesse Wilson        StringBuilder buf = new StringBuilder();
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < s.length(); i++) {
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            char ch = s.charAt(i);
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (ch <= 127) {
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                buf.append(ch);
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                byte[] bytes = new String(new char[] { ch }).getBytes(encoding);
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (int j = 0; j < bytes.length; j++) {
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    buf.append('%');
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    buf.append(digits.charAt((bytes[j] & 0xf0) >> 4));
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    buf.append(digits.charAt(bytes[j] & 0xf));
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return buf.toString();
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Decodes the string argument which is assumed to be encoded in the {@code
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * x-www-form-urlencoded} MIME content type using the UTF-8 encoding scheme.
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <p>
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *'%' and two following hex digit characters are converted to the
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * equivalent byte value. All other characters are passed through
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * unmodified.
1753819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     * <p>
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * e.g. "A%20B%20C %24%25" -> "A B C $%"
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <p>
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Called from URI.getXYZ() methods
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param s
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            java.lang.String The encoded string.
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return java.lang.String The decoded version.
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    static String decode(String s) throws UnsupportedEncodingException {
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
18601021fcb0c9026e81ac2c262caf5e2ec830a7025Jesse Wilson        StringBuilder result = new StringBuilder();
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ByteArrayOutputStream out = new ByteArrayOutputStream();
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < s.length();) {
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            char c = s.charAt(i);
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (c == '%') {
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                out.reset();
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                do {
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (i + 2 >= s.length()) {
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new IllegalArgumentException(Msg.getString(
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                "K01fe", i)); //$NON-NLS-1$
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int d1 = Character.digit(s.charAt(i + 1), 16);
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int d2 = Character.digit(s.charAt(i + 2), 16);
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (d1 == -1 || d2 == -1) {
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new IllegalArgumentException(Msg.getString(
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                "K01ff", s.substring(i, i + 3), //$NON-NLS-1$
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                String.valueOf(i)));
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    out.write((byte) ((d1 << 4) + d2));
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    i += 3;
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } while (i < s.length() && s.charAt(i) == '%');
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                result.append(out.toString(encoding));
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                continue;
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            result.append(c);
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            i++;
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return result.toString();
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
217