jericho 01/04/25 19:08:04 Added: src/webdav/client/src/org/apache/webdav/util URIUtil.java Log: - The new version of URI escaping and unescaping class. - It's gonna integrated with HttpURL and GenricURI class. - So, It's need WebdavResource class to be modified. - NOTICE: It's experimetal. Revision Changes Path 1.1 jakarta-slide/src/webdav/client/src/org/apache/webdav/util/URIUtil.java Index: URIUtil.java =================================================================== /* * $Header: /home/cvs/jakarta-slide/src/webdav/client/src/org/apache/webdav/util/URIUtil.java,v 1.1 2001/04/26 02:08:04 jericho Exp $ * $Revision: 1.1 $ * $Date: 2001/04/26 02:08:04 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * * [Additional notices, if required by prior licensing conditions] * */ package org.apache.webdav.util; import java.io.UnsupportedEncodingException; import java.io.ByteArrayOutputStream; import java.io.OutputStreamWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Map; import java.util.BitSet; /** * General purpose request parsing and encoding utility methods. * * NOTICE: In order to do URI escaping, using the reserved characters defined * in this class is not recommended for the the specific protocol. * * @author Craig R. McClanahan * @author Tim Tye * @author Remy Maucherat * @author Park, Sung-Gu * @version $Revision: 1.1 $ $Date: 2001/04/26 02:08:04 $ */ public class URIUtil { // -------------------------------------------------------------- Constants /** * Array containing the ASCII expression for hexadecimal. */ private static final char[] hexadecimal = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; /** * The default encoding for URI characters. */ private static final String defaultEnc = "UTF-8"; // ----------------------------------------------------- Instance Variables /** * Array containing the alphanum characters set. */ private static BitSet alphanum; /** * Array containing the reserved characters set of the scheme part. */ public static BitSet schemeReserved; /** * Array containing the reserved characters set of the authority part. */ public static BitSet authorityReserved; /** * Array containing the reserved characters set of the userinfo part. */ public static BitSet userinfoReserved; /** * Array containing the reserved characters set of the host part. */ public static BitSet hostReserved; /** * Array containing the reserved characters set of the path part. */ public static BitSet pathReserved; /** * Array containing the reserved characters set of the query. */ public static BitSet queryReserved; // ----------------------------------------------------- Static Initializer static { // Save the alphanum characters that is common to do URI escaping. alphanum = new BitSet(128); for (int i = 'a'; i <= 'z'; i++) { alphanum.set(i); } for (int i = 'A'; i <= 'Z'; i++) { alphanum.set(i); } for (int i = '0'; i <= '9'; i++) { alphanum.set(i); } // Save the reserved characters within the sheme component. schemeReserved = new BitSet(128); /** * Actually, this should be any combination of lower case letters, * digits, plus ("+"), period ("."), or hyphen ("-"). * The upper case letters should be treated as equivalent to lower * case in scheme names. */ schemeReserved.set('+'); schemeReserved.set('.'); schemeReserved.set('-'); // Save the reserved characters within the authority component. authorityReserved = new BitSet(128); authorityReserved.set(';'); authorityReserved.set(':'); authorityReserved.set('@'); authorityReserved.set('?'); authorityReserved.set('/'); // Save the reserved characters within the userinfo component. userinfoReserved = new BitSet(128); userinfoReserved.set(';'); userinfoReserved.set(':'); userinfoReserved.set('&'); userinfoReserved.set('='); userinfoReserved.set('+'); userinfoReserved.set('$'); userinfoReserved.set(','); // Save the reserved characters within the host component. hostReserved = new BitSet(128); hostReserved.set('.'); hostReserved.set('-'); // Save the reserved characters within the path component. pathReserved = new BitSet(128); pathReserved.set('/'); pathReserved.set(';'); pathReserved.set('='); pathReserved.set('?'); // Save the reserved characters within the query component. queryReserved = new BitSet(128); queryReserved.set(';'); queryReserved.set('/'); queryReserved.set('?'); queryReserved.set(':'); queryReserved.set('@'); queryReserved.set('&'); queryReserved.set('='); queryReserved.set('+'); queryReserved.set(','); queryReserved.set('$'); } // -------------------------------------------------------- Private Methods /** * Convert a byte character value to hexidecimal digit value. * * @param b the character value byte */ private static synchronized byte convertHexDigit(byte b) { if ((b >= '0') && (b <= '9')) return (byte)(b - '0'); if ((b >= 'a') && (b <= 'f')) return (byte)(b - 'a' + 10); if ((b >= 'A') && (b <= 'F')) return (byte)(b - 'A' + 10); return 0; } // --------------------------------------------------------- Public Methods /** * Unescape and return the specified URI-escaped String. * When the byte array is converted to a string, the system default * character encoding is used. In order to solve this problem, the * default encoding should be used. * * @param str The uri-escaped string * @exception IllegalArgumentException if a '%' character is not followed * by a valid 2-digit hexadecimal number */ public static String unescape(String str) { return unescape(str, defaultEnc); } /** * Unescape and return the specified URI-escaped String. * * @param str The uri-escaped string. * @param enc The encoding to use. * @exception IllegalArgumentException if a '%' character is not followed * by a valid 2-digit hexadecimal number */ public static String unescape(String str, String enc) { return (str == null) ? null : unescape(str.getBytes(), enc); } /** * Unescape and return the specified URI-escaped byte array. * * @param bytes The uri-escaped byte array * @exception IllegalArgumentException if a '%' character is not followed * by a valid 2-digit hexadecimal number */ public static String unescape(byte[] bytes) { return unescape(bytes, defaultEnc); } /** * Unescape and return the specified URI-escaped byte array. * * @param bytes The uri-escaped byte array * @param enc The encoding to use * @exception IllegalArgumentException if a '%' character is not followed * by a valid 2-digit hexadecimal number */ public static synchronized String unescape(byte[] bytes, String enc) { if (bytes == null) return (null); int len = bytes.length; int ix = 0; int ox = 0; while (ix < len) { byte b = bytes[ix++]; // Get byte to test if (b == '+') { b = (byte)' '; } else if (b == '%') { b = (byte) ((convertHexDigit(bytes[ix++]) << 4) + convertHexDigit(bytes[ix++])); } bytes[ox++] = b; } if (enc != null) { try { return new String(bytes, 0, ox, enc); } catch (Exception e) { e.printStackTrace(); } } return new String(bytes, 0, ox); } /** * URI rewriter. * * @param str The string which has to be rewiten */ public static String escape(String str) { return escape(str, defaultEnc); } /** * URI rewriter. * * @param str The string which has to be rewritten. * @param enc The encoding to use. */ public static String escape(String str, String enc) { return escape(str, enc, null); } /** * URI rewriter. * * @param str The string which has to be rewritten. * @param allowed The additional allowed characters not to escape. */ public static String escape(String str, BitSet allowed) { return escape(str, defaultEnc, allowed); } /** * URI rewriter. * * @param str The string which has to be rewritten. * @param enc The encoding to use. * @param allowed The additional allowed characters not to escape. */ public static synchronized String escape(String str, String enc, BitSet allowed) { if (str == null) return (null); int maxBytesPerChar = 10; int caseDiff = ('a' - 'A'); StringBuffer rewrittenStr = new StringBuffer(str.length()); ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar); OutputStreamWriter writer = null; try { // The same encoding as the one specified above should be used. writer = new OutputStreamWriter(buf, enc); } catch (Exception e) { e.printStackTrace(); writer = new OutputStreamWriter(buf); } for (int i = 0; i < str.length(); i++) { int c = (int) str.charAt(i); if (alphanum.get(c)) { rewrittenStr.append((char)c); } else if (allowed != null && allowed.get(c)) { rewrittenStr.append((char)c); } else { // convert to external encoding before hex conversion try { writer.write(c); writer.flush(); } catch(IOException e) { buf.reset(); continue; } byte[] ba = buf.toByteArray(); for (int j = 0; j < ba.length; j++) { // Converting each byte in the buffer byte toEscape = ba[j]; rewrittenStr.append('%'); int low = (int) (toEscape & 0x0f); int high = (int) ((toEscape & 0xf0) >> 4); rewrittenStr.append(hexadecimal[high]); rewrittenStr.append(hexadecimal[low]); } buf.reset(); } } return rewrittenStr.toString(); } }
