URLDecoder.java revision adc854b798c1cfe3bfd4c27d68d5cee38ca617da
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.net;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.ByteArrayOutputStream;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.UnsupportedEncodingException;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.apache.harmony.luni.util.Msg;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.apache.harmony.luni.util.Util;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This class is used to decode a string which is encoded in the {@code
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * application/x-www-form-urlencoded} MIME content type.
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @since Android 1.0
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class URLDecoder {
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes the argument which is assumed to be encoded in the {@code
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * x-www-form-urlencoded} MIME content type.
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *'+' will be converted to space, '%' and two following hex digit
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * characters are converted to the equivalent byte value. All other
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * characters are passed through unmodified. For example "A+B+C %24%25" ->
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * "A B C $%".
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * </p>
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param s
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the encoded string.
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the decoded clear-text representation of the given string.
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @deprecated use {@link #decode(String, String)} instead.
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @since Android 1.0
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Deprecated
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static String decode(String s) {
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return Util.decode(s, true);
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes the argument which is assumed to be encoded in the {@code
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * x-www-form-urlencoded} MIME content type using the specified encoding
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * scheme.
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *'+' will be converted to space, '%' and two following hex digit
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * characters are converted to the equivalent byte value. All other
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * characters are passed through unmodified. For example "A+B+C %24%25" ->
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * "A B C $%".
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * </p>
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param s
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the encoded string.
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param enc
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the encoding scheme to be used.
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the decoded clear-text representation of the given string.
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws UnsupportedEncodingException
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the specified encoding scheme is invalid.
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @since Android 1.0
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static String decode(String s, String enc)
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws UnsupportedEncodingException {
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (enc == null) {
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NullPointerException();
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // If the given encoding is an empty string throw an exception.
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (enc.length() == 0) {
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new UnsupportedEncodingException(Msg
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getString("K00a5", "enc")); //$NON-NLS-1$ //$NON-NLS-2$
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        StringBuffer result = new StringBuffer(s.length());
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ByteArrayOutputStream out = new ByteArrayOutputStream();
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (int i = 0; i < s.length();) {
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            char c = s.charAt(i);
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (c == '+') {
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                result.append(' ');
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if (c == '%') {
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                out.reset();
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                do {
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (i + 2 >= s.length()) {
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        throw new IllegalArgumentException(Msg.getString(
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                "K01fe", i)); //$NON-NLS-1$
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    int d1 = Character.digit(s.charAt(i + 1), 16);
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    int d2 = Character.digit(s.charAt(i + 2), 16);
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (d1 == -1 || d2 == -1) {
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        throw new IllegalArgumentException(Msg.getString(
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                "K01ff", //$NON-NLS-1$
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                s.substring(i, i + 3), String.valueOf(i)));
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    out.write((byte) ((d1 << 4) + d2));
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    i += 3;
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } while (i < s.length() && s.charAt(i) == '%');
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                result.append(out.toString(enc));
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                continue;
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                result.append(c);
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            i++;
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result.toString();
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
121