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 27/** 28 * This class is used to decode a string which is encoded in the {@code 29 * application/x-www-form-urlencoded} MIME content type. 30 */ 31public class URLDecoder { 32 /** 33 * Decodes the argument which is assumed to be encoded in the {@code 34 * x-www-form-urlencoded} MIME content type. 35 * <p> 36 *'+' will be converted to space, '%' and two following hex digit 37 * characters are converted to the equivalent byte value. All other 38 * characters are passed through unmodified. For example "A+B+C %24%25" -> 39 * "A B C $%". 40 * 41 * @param s 42 * the encoded string. 43 * @return the decoded clear-text representation of the given string. 44 * @deprecated use {@link #decode(String, String)} instead. 45 */ 46 @Deprecated 47 public static String decode(String s) { 48 return decode(s, Charset.defaultCharset()); 49 } 50 51 /** 52 * Decodes the argument which is assumed to be encoded in the {@code 53 * x-www-form-urlencoded} MIME content type using the specified encoding 54 * scheme. 55 * <p> 56 *'+' will be converted to space, '%' and two following hex digit 57 * characters are converted to the equivalent byte value. All other 58 * characters are passed through unmodified. For example "A+B+C %24%25" -> 59 * "A B C $%". 60 * 61 * @param s 62 * the encoded string. 63 * @param encoding 64 * the encoding scheme to be used. 65 * @return the decoded clear-text representation of the given string. 66 * @throws UnsupportedEncodingException 67 * if the specified encoding scheme is invalid. 68 */ 69 public static String decode(String s, String encoding) throws UnsupportedEncodingException { 70 if (encoding == null) { 71 throw new NullPointerException(); 72 } 73 if (encoding.isEmpty()) { 74 throw new UnsupportedEncodingException(encoding); 75 } 76 77 if (s.indexOf('%') == -1) { 78 if (s.indexOf('+') == -1) 79 return s; 80 char[] str = s.toCharArray(); 81 for (int i = 0; i < str.length; i++) { 82 if (str[i] == '+') 83 str[i] = ' '; 84 } 85 return new String(str); 86 } 87 88 Charset charset = null; 89 try { 90 charset = Charset.forName(encoding); 91 } catch (IllegalCharsetNameException e) { 92 throw (UnsupportedEncodingException) (new UnsupportedEncodingException( 93 encoding).initCause(e)); 94 } catch (UnsupportedCharsetException e) { 95 throw (UnsupportedEncodingException) (new UnsupportedEncodingException( 96 encoding).initCause(e)); 97 } 98 99 return decode(s, charset); 100 } 101 102 private static String decode(String s, Charset charset) { 103 104 char[] str_buf = new char[s.length()]; 105 byte[] buf = new byte[s.length() / 3]; 106 int buf_len = 0; 107 108 for (int i = 0; i < s.length();) { 109 char c = s.charAt(i); 110 if (c == '+') { 111 str_buf[buf_len] = ' '; 112 } else if (c == '%') { 113 114 int len = 0; 115 do { 116 if (i + 2 >= s.length()) { 117 throw new IllegalArgumentException("Incomplete % sequence at: " + i); 118 } 119 int d1 = Character.digit(s.charAt(i + 1), 16); 120 int d2 = Character.digit(s.charAt(i + 2), 16); 121 if (d1 == -1 || d2 == -1) { 122 throw new IllegalArgumentException("Invalid % sequence " + 123 s.substring(i, i + 3) + " at " + i); 124 } 125 buf[len++] = (byte) ((d1 << 4) + d2); 126 i += 3; 127 } while (i < s.length() && s.charAt(i) == '%'); 128 129 CharBuffer cb = charset.decode(ByteBuffer.wrap(buf, 0, len)); 130 len = cb.length(); 131 System.arraycopy(cb.array(), 0, str_buf, buf_len, len); 132 buf_len += len; 133 continue; 134 } else { 135 str_buf[buf_len] = c; 136 } 137 i++; 138 buf_len++; 139 } 140 return new String(str_buf, 0, buf_len); 141 } 142} 143