1 /*
   2  * Copyright (c) 1999, 2001, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.jndi.toolkit.url;
  27 
  28 import java.net.MalformedURLException;
  29 import java.io.UnsupportedEncodingException;
  30 import java.net.URLDecoder;
  31 
  32 /**
  33  * Utilities for dealing with URLs.
  34  * @author Vincent Ryan
  35  */
  36 
  37 final public class UrlUtil {
  38 
  39     // To prevent creation of this static class
  40     private UrlUtil() {
  41     }
  42 
  43     /**
  44      * Decode a URI string (according to RFC 2396).
  45      */
  46     public static final String decode(String s) throws MalformedURLException {
  47         try {
  48             return decode(s, "8859_1");
  49         } catch (UnsupportedEncodingException e) {
  50             // ISO-Latin-1 should always be available?
  51             throw new MalformedURLException("ISO-Latin-1 decoder unavailable");
  52         }
  53     }
  54 
  55     /**
  56      * Decode a URI string (according to RFC 2396).
  57      *
  58      * Three-character sequences '%xy', where 'xy' is the two-digit
  59      * hexadecimal representation of the lower 8-bits of a character,
  60      * are decoded into the character itself.
  61      *
  62      * The string is subsequently converted using the specified encoding
  63      */
  64     public static final String decode(String s, String enc)
  65             throws MalformedURLException, UnsupportedEncodingException {
  66         try {
  67             return URLDecoder.decode(s, enc);
  68         } catch (IllegalArgumentException iae) {
  69             MalformedURLException mue = new MalformedURLException("Invalid URI encoding: " + s);
  70             mue.initCause(iae);
  71             throw mue;
  72         }
  73     }
  74 
  75     /**
  76      * Encode a string for inclusion in a URI (according to RFC 2396).
  77      *
  78      * Unsafe characters are escaped by encoding them in three-character
  79      * sequences '%xy', where 'xy' is the two-digit hexadecimal representation
  80      * of the lower 8-bits of the character.
  81      *
  82      * The question mark '?' character is also escaped, as required by RFC 2255.
  83      *
  84      * The string is first converted to the specified encoding.
  85      * For LDAP (2255), the encoding must be UTF-8.
  86      */
  87     public static final String encode(String s, String enc)
  88         throws UnsupportedEncodingException {
  89 
  90         byte[] bytes = s.getBytes(enc);
  91         int count = bytes.length;
  92 
  93         /*
  94          * From RFC 2396:
  95          *
  96          *     mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
  97          * reserved = ";" | "/" | ":" | "?" | "@" | "&" | "=" | "+" | "$" | ","
  98          */
  99         final String allowed = "=,+;.'-@&/$_()!~*:"; // '?' is omitted
 100         char[] buf = new char[3 * count];
 101         int j = 0;
 102 
 103         for (int i = 0; i < count; i++) {
 104             if ((bytes[i] >= 0x61 && bytes[i] <= 0x7A) || // a..z
 105                 (bytes[i] >= 0x41 && bytes[i] <= 0x5A) || // A..Z
 106                 (bytes[i] >= 0x30 && bytes[i] <= 0x39) || // 0..9
 107                 (allowed.indexOf(bytes[i]) >= 0)) {
 108                 buf[j++] = (char) bytes[i];
 109             } else {
 110                 buf[j++] = '%';
 111                 buf[j++] = Character.forDigit(0xF & (bytes[i] >>> 4), 16);
 112                 buf[j++] = Character.forDigit(0xF & bytes[i], 16);
 113             }
 114         }
 115         return new String(buf, 0, j);
 116     }
 117 }