001: /*
002: * Copyright 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.jndi.toolkit.url;
027:
028: import java.net.MalformedURLException;
029: import java.io.UnsupportedEncodingException;
030:
031: /**
032: * Utilities for dealing with URLs.
033: * @author Vincent Ryan
034: * @version 1.16 07/05/05
035: */
036:
037: final public class UrlUtil {
038:
039: // To prevent creation of this static class
040: private UrlUtil() {
041: }
042:
043: /**
044: * Decode a URI string (according to RFC 2396).
045: */
046: public static final String decode(String s)
047: throws MalformedURLException {
048: try {
049: return decode(s, "8859_1");
050: } catch (UnsupportedEncodingException e) {
051: // ISO-Latin-1 should always be available?
052: throw new MalformedURLException(
053: "ISO-Latin-1 decoder unavailable");
054: }
055: }
056:
057: /**
058: * Decode a URI string (according to RFC 2396).
059: *
060: * Three-character sequences '%xy', where 'xy' is the two-digit
061: * hexadecimal representation of the lower 8-bits of a character,
062: * are decoded into the character itself.
063: *
064: * The string is subsequently converted using the specified encoding
065: */
066: public static final String decode(String s, String enc)
067: throws MalformedURLException, UnsupportedEncodingException {
068:
069: int length = s.length();
070: byte[] bytes = new byte[length];
071: int j = 0;
072:
073: for (int i = 0; i < length; i++) {
074: if (s.charAt(i) == '%') {
075: i++; // skip %
076: try {
077: bytes[j++] = (byte) Integer.parseInt(s.substring(i,
078: i + 2), 16);
079:
080: } catch (Exception e) {
081: throw new MalformedURLException(
082: "Invalid URI encoding: " + s);
083: }
084: i++; // skip first hex char; for loop will skip second one
085: } else {
086: bytes[j++] = (byte) s.charAt(i);
087: }
088: }
089:
090: return new String(bytes, 0, j, enc);
091: }
092:
093: /**
094: * Encode a string for inclusion in a URI (according to RFC 2396).
095: *
096: * Unsafe characters are escaped by encoding them in three-character
097: * sequences '%xy', where 'xy' is the two-digit hexadecimal representation
098: * of the lower 8-bits of the character.
099: *
100: * The question mark '?' character is also escaped, as required by RFC 2255.
101: *
102: * The string is first converted to the specified encoding.
103: * For LDAP (2255), the encoding must be UTF-8.
104: */
105: public static final String encode(String s, String enc)
106: throws UnsupportedEncodingException {
107:
108: byte[] bytes = s.getBytes(enc);
109: int count = bytes.length;
110:
111: /*
112: * From RFC 2396:
113: *
114: * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
115: * reserved = ";" | "/" | ":" | "?" | "@" | "&" | "=" | "+" | "$" | ","
116: */
117: final String allowed = "=,+;.'-@&/$_()!~*:"; // '?' is omitted
118: char[] buf = new char[3 * count];
119: int j = 0;
120:
121: for (int i = 0; i < count; i++) {
122: if ((bytes[i] >= 0x61 && bytes[i] <= 0x7A) || // a..z
123: (bytes[i] >= 0x41 && bytes[i] <= 0x5A) || // A..Z
124: (bytes[i] >= 0x30 && bytes[i] <= 0x39) || // 0..9
125: (allowed.indexOf(bytes[i]) >= 0)) {
126: buf[j++] = (char) bytes[i];
127: } else {
128: buf[j++] = '%';
129: buf[j++] = Character.forDigit(0xF & (bytes[i] >>> 4),
130: 16);
131: buf[j++] = Character.forDigit(0xF & bytes[i], 16);
132: }
133: }
134: return new String(buf, 0, j);
135: }
136: }
|