1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.net; 19 20import java.io.UnsupportedEncodingException; 21import java.nio.ByteBuffer; 22import java.nio.CharBuffer; 23import java.nio.charset.Charset; 24import java.nio.charset.IllegalCharsetNameException; 25import java.nio.charset.UnsupportedCharsetException; 26 27import org.apache.harmony.luni.util.Msg; 28 29/** 30 * This class is used to decode a string which is encoded in the {@code 31 * application/x-www-form-urlencoded} MIME content type. 32 */ 33public class URLDecoder { 34 35 static Charset defaultCharset; 36 37 /** 38 * Decodes the argument which is assumed to be encoded in the {@code 39 * x-www-form-urlencoded} MIME content type. 40 * <p> 41 *'+' will be converted to space, '%' and two following hex digit 42 * characters are converted to the equivalent byte value. All other 43 * characters are passed through unmodified. For example "A+B+C %24%25" -> 44 * "A B C $%". 45 * 46 * @param s 47 * the encoded string. 48 * @return the decoded clear-text representation of the given string. 49 * @deprecated use {@link #decode(String, String)} instead. 50 */ 51 @Deprecated 52 public static String decode(String s) { 53 54 if (defaultCharset == null) { 55 try { 56 defaultCharset = Charset.forName( 57 System.getProperty("file.encoding")); //$NON-NLS-1$ 58 } catch (IllegalCharsetNameException e) { 59 // Ignored 60 } catch (UnsupportedCharsetException e) { 61 // Ignored 62 } 63 64 if (defaultCharset == null) { 65 defaultCharset = Charset.forName("ISO-8859-1"); //$NON-NLS-1$ 66 } 67 } 68 return decode(s, defaultCharset); 69 } 70 71 /** 72 * Decodes the argument which is assumed to be encoded in the {@code 73 * x-www-form-urlencoded} MIME content type using the specified encoding 74 * scheme. 75 * <p> 76 *'+' will be converted to space, '%' and two following hex digit 77 * characters are converted to the equivalent byte value. All other 78 * characters are passed through unmodified. For example "A+B+C %24%25" -> 79 * "A B C $%". 80 * 81 * @param s 82 * the encoded string. 83 * @param enc 84 * the encoding scheme to be used. 85 * @return the decoded clear-text representation of the given string. 86 * @throws UnsupportedEncodingException 87 * if the specified encoding scheme is invalid. 88 */ 89 public static String decode(String s, String enc) 90 throws UnsupportedEncodingException { 91 92 if (enc == null) { 93 throw new NullPointerException(); 94 } 95 96 // If the given encoding is an empty string throw an exception. 97 if (enc.length() == 0) { 98 throw new UnsupportedEncodingException( 99 // K00a5=Invalid parameter - {0} 100 Msg.getString("K00a5", "enc")); //$NON-NLS-1$ //$NON-NLS-2$ 101 } 102 103 if (s.indexOf('%') == -1) { 104 if (s.indexOf('+') == -1) 105 return s; 106 char str[] = s.toCharArray(); 107 for (int i = 0; i < str.length; i++) { 108 if (str[i] == '+') 109 str[i] = ' '; 110 } 111 return new String(str); 112 } 113 114 Charset charset = null; 115 try { 116 charset = Charset.forName(enc); 117 } catch (IllegalCharsetNameException e) { 118 throw (UnsupportedEncodingException) (new UnsupportedEncodingException( 119 enc).initCause(e)); 120 } catch (UnsupportedCharsetException e) { 121 throw (UnsupportedEncodingException) (new UnsupportedEncodingException( 122 enc).initCause(e)); 123 } 124 125 return decode(s, charset); 126 } 127 128 private static String decode(String s, Charset charset) { 129 130 char str_buf[] = new char[s.length()]; 131 byte buf[] = new byte[s.length() / 3]; 132 int buf_len = 0; 133 134 for (int i = 0; i < s.length();) { 135 char c = s.charAt(i); 136 if (c == '+') { 137 str_buf[buf_len] = ' '; 138 } else if (c == '%') { 139 140 int len = 0; 141 do { 142 if (i + 2 >= s.length()) { 143 throw new IllegalArgumentException( 144 // K01fe=Incomplete % sequence at\: {0} 145 Msg.getString("K01fe", i)); //$NON-NLS-1$ 146 } 147 int d1 = Character.digit(s.charAt(i + 1), 16); 148 int d2 = Character.digit(s.charAt(i + 2), 16); 149 if (d1 == -1 || d2 == -1) { 150 throw new IllegalArgumentException( 151 // K01ff=Invalid % sequence ({0}) at\: {1} 152 Msg.getString( 153 "K01ff", //$NON-NLS-1$ 154 s.substring(i, i + 3), 155 String.valueOf(i))); 156 } 157 buf[len++] = (byte) ((d1 << 4) + d2); 158 i += 3; 159 } while (i < s.length() && s.charAt(i) == '%'); 160 161 CharBuffer cb = charset.decode(ByteBuffer.wrap(buf, 0, len)); 162 len = cb.length(); 163 System.arraycopy(cb.array(), 0, str_buf, buf_len, len); 164 buf_len += len; 165 continue; 166 } else { 167 str_buf[buf_len] = c; 168 } 169 i++; 170 buf_len++; 171 } 172 return new String(str_buf, 0, buf_len); 173 } 174} 175