merge of 'daa35ac8b482063c4db4b6205ca5dacc045080a4'

and 'e19c106344aa97ad1765e79df75f96182f89d102'
This commit is contained in:
sponge
2010-12-19 00:23:10 +00:00
3 changed files with 1348 additions and 1 deletions

View File

@ -0,0 +1,352 @@
// ========================================================================
// $Id: FileResource.java,v 1.31 2006/01/04 13:55:31 gregwilkins Exp $
// Copyright 1996-2004 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
package org.mortbay.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.security.Permission;
import org.apache.commons.logging.Log;
import org.mortbay.log.LogFactory;
/* ------------------------------------------------------------ */
/** File Resource.
*
* Handle resources of implied or explicit file type.
* This class can check for aliasing in the filesystem (eg case
* insensitivity). By default this is turned on if the platform does
* not have the "/" path separator, or it can be controlled with the
* "org.mortbay.util.FileResource.checkAliases" system parameter.
*
* If alias checking is turned on, then aliased resources are
* treated as if they do not exist, nor can they be created.
*
* @version $Revision: 1.31 $
* @author Greg Wilkins (gregw)
*/
public class FileResource extends URLResource
{
private static Log log = LogFactory.getLog(Credential.class);
private static boolean __checkAliases;
static
{
__checkAliases=
"true".equalsIgnoreCase
(System.getProperty("org.mortbay.util.FileResource.checkAliases","true"));
if (__checkAliases)
log.info("Checking Resource aliases");
}
/* ------------------------------------------------------------ */
private File _file;
private transient URL _alias=null;
private transient boolean _aliasChecked=false;
/* ------------------------------------------------------------------------------- */
/** setCheckAliases.
* @param checkAliases True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
*/
public static void setCheckAliases(boolean checkAliases)
{
__checkAliases=checkAliases;
}
/* ------------------------------------------------------------------------------- */
/** getCheckAliases.
* @return True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
*/
public static boolean getCheckAliases()
{
return __checkAliases;
}
/* -------------------------------------------------------- */
FileResource(URL url)
throws IOException, URISyntaxException
{
super(url,null);
try
{
// Try standard API to convert URL to file.
_file =new File(new URI(url.toString()));
}
catch (Exception e)
{
LogSupport.ignore(log,e);
try
{
// Assume that File.toURL produced unencoded chars. So try
// encoding them.
String urls=
"file:"+org.mortbay.util.URI.encodePath(url.toString().substring(5));
_file =new File(new URI(urls));
}
catch (Exception e2)
{
LogSupport.ignore(log,e2);
// Still can't get the file. Doh! try good old hack!
checkConnection();
Permission perm = _connection.getPermission();
_file = new File(perm==null?url.getFile():perm.getName());
}
}
if (_file.isDirectory() && !_urlString.endsWith("/"))
_urlString=_urlString+"/";
}
/* -------------------------------------------------------- */
FileResource(URL url, URLConnection connection, File file)
{
super(url,connection);
_file=file;
if (_file.isDirectory() && !_urlString.endsWith("/"))
_urlString=_urlString+"/";
}
/* -------------------------------------------------------- */
public Resource addPath(String path)
throws IOException,MalformedURLException
{
FileResource r=null;
if (!isDirectory())
{
r=(FileResource)super.addPath(path);
}
else
{
path = org.mortbay.util.URI.canonicalPath(path);
// treat all paths being added as relative
String rel=path;
if (path.startsWith("/"))
rel = path.substring(1);
File newFile = new File(_file,rel.replace('/', File.separatorChar));
r=new FileResource(newFile.toURI().toURL(),null,newFile);
}
String encoded=org.mortbay.util.URI.encodePath(path);
int expected=r._urlString.length()-encoded.length();
int index = r._urlString.lastIndexOf(encoded, expected);
if (expected!=index && ((expected-1)!=index || path.endsWith("/") || !r.isDirectory()))
{
r._alias=r._url;
r._aliasChecked=true;
}
return r;
}
/* ------------------------------------------------------------ */
public URL getAlias()
{
if (__checkAliases) {
if (!_aliasChecked)
{
try
{
String abs=_file.getAbsolutePath();
String can=_file.getCanonicalPath();
if (abs.length()!=can.length() || !abs.equals(can))
_alias=new File(can).toURI().toURL();
_aliasChecked=true;
if (_alias!=null && log.isDebugEnabled())
{
log.debug("ALIAS abs="+abs);
log.debug("ALIAS can="+can);
}
}
catch(Exception e)
{
log.warn(LogSupport.EXCEPTION,e);
return getURL();
}
}
} else return null;
return _alias;
}
/* -------------------------------------------------------- */
/**
* Returns true if the resource exists.
*/
public boolean exists()
{
return _file.exists();
}
/* -------------------------------------------------------- */
/**
* Returns the last modified time
*/
public long lastModified()
{
return _file.lastModified();
}
/* -------------------------------------------------------- */
/**
* Returns true if the respresenetd resource is a container/directory.
*/
public boolean isDirectory()
{
return _file.isDirectory();
}
/* --------------------------------------------------------- */
/**
* Return the length of the resource
*/
public long length()
{
return _file.length();
}
/* --------------------------------------------------------- */
/**
* Returns the name of the resource
*/
public String getName()
{
return _file.getAbsolutePath();
}
/* ------------------------------------------------------------ */
/**
* Returns an File representing the given resource or NULL if this
* is not possible.
*/
public File getFile()
{
return _file;
}
/* --------------------------------------------------------- */
/**
* Returns an input stream to the resource
*/
public InputStream getInputStream() throws IOException
{
return new FileInputStream(_file);
}
/* --------------------------------------------------------- */
/**
* Returns an output stream to the resource
*/
public OutputStream getOutputStream()
throws java.io.IOException, SecurityException
{
return new FileOutputStream(_file);
}
/* --------------------------------------------------------- */
/**
* Deletes the given resource
*/
public boolean delete()
throws SecurityException
{
return _file.delete();
}
/* --------------------------------------------------------- */
/**
* Rename the given resource
*/
public boolean renameTo( Resource dest)
throws SecurityException
{
if( dest instanceof FileResource)
return _file.renameTo( ((FileResource)dest)._file);
else
return false;
}
/* --------------------------------------------------------- */
/**
* Returns a list of resources contained in the given resource
*/
public String[] list()
{
String[] list =_file.list();
if (list==null)
return null;
for (int i=list.length;i-->0;)
{
if (new File(_file,list[i]).isDirectory() &&
!list[i].endsWith("/"))
list[i]+="/";
}
return list;
}
/* ------------------------------------------------------------ */
/** Encode according to this resource type.
* File URIs are encoded.
* @param uri URI to encode.
* @return The uri unchanged.
*/
public String encode(String uri)
{
return uri;
}
/* ------------------------------------------------------------ */
/**
* @param o
* @return
*/
public boolean equals( Object o)
{
if (this == o)
return true;
if (null == o || ! (o instanceof FileResource))
return false;
FileResource f=(FileResource)o;
return f._file == _file || (null != _file && _file.equals(f._file));
}
/* ------------------------------------------------------------ */
/**
* @return the hashcode.
*/
public int hashCode()
{
return null == _file ? super.hashCode() : _file.hashCode();
}
}

View File

@ -392,7 +392,7 @@ public abstract class Resource implements Serializable
buf.append(path);
buf.append("\">");
buf.append(StringUtil.replace(StringUtil.replace(ls[i],"<","&lt;"),">","&gt;"));
buf.append("&nbsp;");
buf.append("</A>&nbsp;");
buf.append("</TD><TD ALIGN=right>");
buf.append(item.length());
buf.append(" bytes&nbsp;</TD><TD>");

View File

@ -0,0 +1,995 @@
// ========================================================================
// $Id: URI.java,v 1.40 2009/05/16 02:02:00 gregwilkins Exp $
// Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
package org.mortbay.util;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.mortbay.log.LogFactory;
/* ------------------------------------------------------------ */
/** URI Holder.
* This class assists with the decoding and encoding or HTTP URI's.
* It differs from the java.net.URL class as it does not provide
* communications ability, but it does assist with query string
* formatting.
* <P>ISO_8859_1 encoding is used by default for % encoded characters. This
* may be overridden with the org.mortbay.util.URI.charset system property.
* @see UrlEncoded
* @version $Id: URI.java,v 1.40 2009/05/16 02:02:00 gregwilkins Exp $
* @author Greg Wilkins (gregw)
*/
public class URI
implements Cloneable
{
private static Log log = LogFactory.getLog(URI.class);
public static final String __CHARSET=System.getProperty("org.mortbay.util.URI.charset",StringUtil.__UTF_8);
public static final boolean __CHARSET_IS_DEFAULT=__CHARSET.equals(StringUtil.__UTF_8);
/* ------------------------------------------------------------ */
private String _uri;
private String _scheme;
private String _host;
private int _port;
private String _path;
private String _encodedPath;
private String _query;
private UrlEncoded _parameters;
private boolean _dirty;
private static String unreserved = "/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.~";
private static String reserved = "!*'();:@&=+$,?%#[]";
private static String hexchars = "0123456789ABCDEF";
/* ------------------------------------------------------------ */
/** Copy Constructor .
* @param uri
*/
public URI(URI uri)
throws IllegalArgumentException
{
_uri=uri.toString();
_scheme=uri._scheme;
_host=uri._host;
_port=uri._port;
_path=uri._path;
_encodedPath=uri._encodedPath;
_query=uri._query;
if (uri._parameters!=null)
_parameters=(UrlEncoded)uri._parameters.clone();
_dirty=false;
}
/* ------------------------------------------------------------ */
/** Construct from a String.
* The string must contain a URI path, but optionaly may contain a
* scheme, host, port and query string.
*
* @param uri [scheme://host[:port]]/path[?query]
*/
public URI(String uri)
throws IllegalArgumentException
{
setURI(uri);
}
/* ------------------------------------------------------------ */
public void setURI(String uri)
throws IllegalArgumentException
{
try
{
_uri=uri;
_scheme=null;
_host=null;
_port=0;
_path=null;
_encodedPath=null;
_query=null;
if (_parameters!=null)
_parameters.clear();
// Scan _uri for host, port, path & query
int maxi=uri.length()-1;
int mark=0;
int state=0;
int i=0;
if (maxi==0 || uri.charAt(0)=='/' && uri.charAt(1)!='/')
{
state=3;
_scheme=null;
_host=null;
_port=0;
}
else
{
for (i=0;state<3 && i<=maxi;i++)
{
char c=uri.charAt(i);
switch(state)
{
case 0: // looking for scheme or path
if (c==':' &&
uri.charAt(i+1)=='/' &&
uri.charAt(i+2)=='/')
{
// found end of scheme & start of host
_scheme=uri.substring(mark,i);
i+=2;
mark=i+1;
state=1;
}
else if (i==0 && c=='/')
{
// Found path
state=3;
}
else if (i==0 && c=='*')
{
state=5;
_path="*";
_encodedPath="*";
}
continue;
case 1: // Get host & look for port or path
if (c==':')
{
// found port
_host=uri.substring(mark,i);
mark=i+1;
state=2;
}
else if (c=='/')
{
// found path
_host=uri.substring(mark,i);
mark=i;
state=3;
}
continue;
case 2: // Get port & look for path
if (c=='/')
{
_port=TypeUtil.parseInt(uri,mark,i-mark,10);
mark=i;
state=3;
}
continue;
}
}
}
// State 3 - Get path & look for query
_query=null;
for (i++;i<=maxi;i++)
{
char c=uri.charAt(i);
if (c=='?')
{
// Found query
_encodedPath=uri.substring(mark,i);
_path=decodePath(_encodedPath);
mark=i+1;
state=4;
break;
}
}
// complete last state
switch(state)
{
case 0:
_dirty=false;
_encodedPath=_uri;
_path=decodePath(_encodedPath);
break;
case 1:
_dirty=true;
_encodedPath="/";
_path=_encodedPath;
_host=uri.substring(mark);
break;
case 2:
_dirty=true;
_encodedPath="/";
_path=_encodedPath;
_port=TypeUtil.parseInt(uri,mark,-1,10);
break;
case 3:
_dirty=(mark==maxi);
_encodedPath=uri.substring(mark);
_path=decodePath(_encodedPath);
break;
case 4:
_dirty=false;
if (mark<=maxi)
_query=uri.substring(mark);
break;
case 5:
_dirty=false;
}
if (_query!=null && _query.length()>0)
{
if (_parameters==null)
_parameters= new UrlEncoded();
else
_parameters.clear();
_parameters.decode(_query,__CHARSET);
}
else
_query=null;
}
catch (Exception e)
{
LogSupport.ignore(log,e);
throw new IllegalArgumentException("Malformed URI '"+uri+
"' : "+e.toString());
}
}
/* ------------------------------------------------------------ */
/** Is the URI an absolute URL?
* @return True if the URI has a scheme or host
*/
public boolean isAbsolute()
{
return _scheme!=null || _host!=null;
}
/* ------------------------------------------------------------ */
/** Get the uri scheme.
* @return the URI scheme
*/
public String getScheme()
{
return _scheme;
}
/* ------------------------------------------------------------ */
/** Set the uri scheme.
* @param scheme the uri scheme
*/
public void setScheme(String scheme)
{
_scheme=scheme;
_dirty=true;
}
/* ------------------------------------------------------------ */
/** Get the uri host.
* @return the URI host
*/
public String getHost()
{
return _host;
}
/* ------------------------------------------------------------ */
/** Set the uri host.
* @param host the uri host
*/
public void setHost(String host)
{
_host=host;
_dirty=true;
}
/* ------------------------------------------------------------ */
/** Get the uri port.
* @return the URI port
*/
public int getPort()
{
return _port;
}
/* ------------------------------------------------------------ */
/** Set the uri port.
* A port of 0 implies use the default port.
* @param port the uri port
*/
public void setPort(int port)
{
_port=port;
_dirty=true;
}
/* ------------------------------------------------------------ */
/** Get the uri path.
* @return the URI path
*/
public String getPath()
{
return _path;
}
/* ------------------------------------------------------------ */
/** Get the encoded uri path.
* @return the URI path
*/
public String getEncodedPath()
{
return _encodedPath;
}
/* ------------------------------------------------------------ */
/** Set the uri path.
* @param path the URI path
*/
public void setPath(String path)
{
_path=path;
_encodedPath=encodePath(_path);
_dirty=true;
}
/* ------------------------------------------------------------ */
/** Get the uri query String.
* @return the URI query string
*/
public String getQuery()
{
if (_dirty && _parameters!=null)
{
_query = _parameters.encode(__CHARSET);
if (_query!=null && _query.length()==0)
_query=null;
}
return _query;
}
/* ------------------------------------------------------------ */
/** Set the uri query String.
* @param query the URI query string
*/
public void setQuery(String query)
{
_query=query;
if (_parameters!=null)
_parameters.clear();
else if (query!=null)
_parameters=new UrlEncoded();
if (query!=null)
_parameters.decode(query,__CHARSET);
cleanURI();
}
/* ------------------------------------------------------------ */
/** Get the uri query _parameters names.
* @return Unmodifiable set of URI query _parameters names
*/
public Set getParameterNames()
{
if (_parameters==null)
return Collections.EMPTY_SET;
return _parameters.keySet();
}
/* ------------------------------------------------------------ */
/** Get the uri query _parameters.
* @return the URI query _parameters
*/
public MultiMap getParameters()
{
if (_parameters==null)
_parameters=new UrlEncoded();
_dirty=true;
return _parameters;
}
/* ------------------------------------------------------------ */
/** Get the uri query _parameters.
* @return the URI query _parameters in an unmodifiable map.
*/
public Map getUnmodifiableParameters()
{
if (_parameters==null)
return Collections.EMPTY_MAP;
return Collections.unmodifiableMap(_parameters);
}
/* ------------------------------------------------------------ */
/** Add the uri query _parameters to a MultiMap
*/
public void putParametersTo(MultiMap map)
{
if (_parameters!=null && _parameters.size()>0)
map.putAll(_parameters);
}
/* ------------------------------------------------------------ */
/** Clear the URI _parameters.
*/
public void clearParameters()
{
if (_parameters!=null)
{
_dirty=true;
_parameters.clear();
}
}
/* ------------------------------------------------------------ */
/** Add encoded _parameters.
* @param encoded A HTTP encoded string of _parameters: e.g.. "a=1&b=2"
*/
public void put(String encoded)
{
UrlEncoded params = new UrlEncoded(encoded);
put(params);
}
/* ------------------------------------------------------------ */
/** Add name value pair to the uri query _parameters.
* @param name name of value
* @param value The value, which may be a multi valued list or
* String array.
*/
public Object put(Object name, Object value)
{
return getParameters().put(name,value);
}
/* ------------------------------------------------------------ */
/** Add dictionary to the uri query _parameters.
*/
public void put(Map values)
{
getParameters().putAll(values);
}
/* ------------------------------------------------------------ */
/** Get named value
*/
public String get(String name)
{
if (_parameters==null)
return null;
return (String)_parameters.get(name);
}
/* ------------------------------------------------------------ */
/** Get named multiple values.
* @param name The parameter name
* @return Umodifiable list of values or null
*/
public List getValues(String name)
{
if (_parameters==null)
return null;
return _parameters.getValues(name);
}
/* ------------------------------------------------------------ */
/** Remove named value
*/
public void remove(String name)
{
if (_parameters!=null)
{
_dirty=
_parameters.remove(name)!=null;
}
}
/* ------------------------------------------------------------ */
/** @return the URI string encoded.
*/
public String toString()
{
if (_dirty)
{
getQuery();
cleanURI();
}
return _uri;
}
/* ------------------------------------------------------------ */
private void cleanURI()
{
StringBuffer buf = new StringBuffer(_uri.length()*2);
synchronized(buf)
{
if (_scheme!=null)
{
buf.append(_scheme);
buf.append("://");
buf.append(_host);
if (_port>0)
{
buf.append(':');
buf.append(_port);
}
}
buf.append(_encodedPath);
if (_query!=null && _query.length()>0)
{
buf.append('?');
buf.append(_query);
}
_uri=buf.toString();
_dirty=false;
}
}
/* ------------------------------------------------------------ */
/** Encode a URI path.
* This is the same encoding offered by URLEncoder, except that
* the '/' character is not encoded.
* @param path The path the encode
* @return The encoded path
*/
public static String encodePath(String path)
{
if (path==null || path.length()==0)
return path;
StringBuffer buf = encodePath(null,path);
return buf==null?path:buf.toString();
}
/* ------------------------------------------------------------ */
/** Encode a URI path.
* @param path The path the encode
* @param buf StringBuffer to encode path into (or null)
* @return The StringBuffer or null if no substitutions required.
*/
public static StringBuffer encodePath(StringBuffer buf, String path)
{
// Convert path to native first.
byte[] b = null;
/*
try {
b = path.getBytes(__CHARSET);
} catch(UnsupportedEncodingException ex) {
return null; // Shouldn't be possible.
}
*/
b = path.getBytes();
StringBuffer x = new StringBuffer(b.length);
for(int i=0; i<b.length; i++) {
x.append((char)(b[i]&0xff));
}
String _path = new String(x);
if(buf == null) {
loop:
for(int i = 0; i < _path.length(); i++) {
char c = _path.charAt(i);
String cs = "" + c;
if(reserved.contains(cs) || !unreserved.contains(cs)) {
buf = new StringBuffer(_path.length() << 1);
break loop;
}
}
if(buf == null) {
return null;
}
}
synchronized(buf) {
for(int i = 0; i < _path.length(); i++) {
char c = _path.charAt(i);
String cs = "" + c;
if(reserved.contains(cs) || !unreserved.contains(cs)) {
if((c & 0xff) == c) {
buf.append(gethex(c & 0xff));
} else {
buf.append(gethex((c >> 8) & 0xff));
buf.append(gethex(c & 0xff));
}
} else {
buf.append(c);
}
}
}
return buf;
}
/**
*
* @param decimal value not greater than 255.
* @return a percent sign followed by two hexadecimal digits.
*/
private static String gethex(int decimal) {
return new String("%" + hexchars.charAt(decimal >> 4) + hexchars.charAt(decimal & 0xF));
}
/* ------------------------------------------------------------ */
/** Encode a URI path.
* @param path The path the encode
* @param buf StringBuffer to encode path into (or null)
* @param encode String of characters to encode. % is always encoded.
* @return The StringBuffer or null if no substitutions required.
*/
public static StringBuffer encodeString(StringBuffer buf,
String path,
String encode)
{
if (buf==null)
{
loop:
for (int i=0;i<path.length();i++)
{
char c=path.charAt(i);
if (c=='%' || encode.indexOf(c)>=0)
{
buf=new StringBuffer(path.length()<<1);
break loop;
}
}
if (buf==null)
return null;
}
synchronized(buf)
{
for (int i=0;i<path.length();i++)
{
char c=path.charAt(i);
if (c=='%' || encode.indexOf(c)>=0)
{
buf.append('%');
StringUtil.append(buf,(byte)(0xff&c),16);
}
else
buf.append(c);
}
}
return buf;
}
/* ------------------------------------------------------------ */
/* Decode a URI path.
* @param path The path the encode
* @param buf StringBuffer to encode path into
*/
public static String decodePath(String path)
{
int len=path.length();
byte[] bytes=null;
int n=0;
boolean noDecode=true;
for (int i=0;i<len;i++)
{
char c = path.charAt(i);
byte b = (byte)(0xff & c);
if (c=='%' && (i+2)<len)
{
noDecode=false;
b=(byte)(0xff&TypeUtil.parseInt(path,i+1,2,16));
i+=2;
}
else if (bytes==null)
{
n++;
continue;
}
if (bytes==null)
{
noDecode=false;
bytes=new byte[len];
for (int j=0;j<n;j++)
bytes[j]=(byte)(0xff & path.charAt(j));
}
bytes[n++]=b;
}
if (noDecode)
return path;
/*
try
{
return new String(bytes,0,n,__CHARSET);
}
catch(UnsupportedEncodingException e)
{
log.warn(LogSupport.EXCEPTION,e);
return new String(bytes,0,n);
}
*/
return new String(bytes,0,n);
}
/* ------------------------------------------------------------ */
/** Clone URI.
* @return cloned URI
*/
public Object clone()
throws CloneNotSupportedException
{
URI u = (URI)super.clone();
if (_parameters!=null)
u._parameters=(UrlEncoded)_parameters.clone();
_dirty=false;
return u;
}
/* ------------------------------------------------------------ */
/** Add two URI path segments.
* Handles null and empty paths, path and query params (eg ?a=b or
* ;JSESSIONID=xxx) and avoids duplicate '/'
* @param p1 URI path segment
* @param p2 URI path segment
* @return Legally combined path segments.
*/
public static String addPaths(String p1, String p2)
{
if (p1==null || p1.length()==0)
{
if (p2==null || p2.length()==0)
return p1;
return p2;
}
if (p2==null || p2.length()==0)
return p1;
int split=p1.indexOf(';');
if (split<0)
split=p1.indexOf('?');
if (split==0)
return p2+p1;
if (split<0)
split=p1.length();
StringBuffer buf = new StringBuffer(p1.length()+p2.length()+2);
buf.append(p1);
if (buf.charAt(split-1)=='/')
{
if (p2.startsWith("/"))
{
buf.deleteCharAt(split-1);
buf.insert(split-1,p2);
}
else
buf.insert(split,p2);
}
else
{
if (p2.startsWith("/"))
buf.insert(split,p2);
else
{
buf.insert(split,'/');
buf.insert(split+1,p2);
}
}
return buf.toString();
}
/* ------------------------------------------------------------ */
/** Return the parent Path.
* Treat a URI like a directory path and return the parent directory.
*/
public static String parentPath(String p)
{
if (p==null || "/".equals(p))
return null;
int slash=p.lastIndexOf('/',p.length()-2);
if (slash>=0)
return p.substring(0,slash+1);
return null;
}
/* ------------------------------------------------------------ */
/** Strip parameters from a path.
* Return path upto any semicolon parameters.
*/
public static String stripPath(String path)
{
if (path==null)
return null;
int semi=path.indexOf(';');
if (semi<0)
return path;
return path.substring(0,semi);
}
/* ------------------------------------------------------------ */
/** Convert a path to a cananonical form.
* All instances of "." and ".." are factored out. Null is returned
* if the path tries to .. above it's root.
* @param path
* @return path or null.
*/
public static String canonicalPath(String path)
{
if (path==null || path.length()==0)
return path;
int end=path.length();
int start = path.lastIndexOf('/', end);
search:
while (end>0)
{
switch(end-start)
{
case 2: // possible single dot
if (path.charAt(start+1)!='.')
break;
break search;
case 3: // possible double dot
if (path.charAt(start+1)!='.' || path.charAt(start+2)!='.')
break;
break search;
}
end=start;
start=path.lastIndexOf('/',end-1);
}
// If we have checked the entire string
if (start>=end)
return path;
StringBuffer buf = new StringBuffer(path);
int delStart=-1;
int delEnd=-1;
int skip=0;
while (end>0)
{
switch(end-start)
{
case 2: // possible single dot
if (buf.charAt(start+1)!='.')
{
if (skip>0 && --skip==0)
{
delStart=start>=0?start:0;
if(delStart>0 && delEnd==buf.length() && buf.charAt(delEnd-1)=='.')
delStart++;
}
break;
}
if(start<0 && buf.length()>2 && buf.charAt(1)=='/' && buf.charAt(2)=='/')
break;
if(delEnd<0)
delEnd=end;
delStart=start;
if (delStart<0 || delStart==0&&buf.charAt(delStart)=='/')
{
delStart++;
if (delEnd<buf.length() && buf.charAt(delEnd)=='/')
delEnd++;
break;
}
if (end==buf.length())
delStart++;
end=start--;
while (start>=0 && buf.charAt(start)!='/')
start--;
continue;
case 3: // possible double dot
if (buf.charAt(start+1)!='.' || buf.charAt(start+2)!='.')
{
if (skip>0 && --skip==0)
{ delStart=start>=0?start:0;
if(delStart>0 && delEnd==buf.length() && buf.charAt(delEnd-1)=='.')
delStart++;
}
break;
}
delStart=start;
if (delEnd<0)
delEnd=end;
skip++;
end=start--;
while (start>=0 && buf.charAt(start)!='/')
start--;
continue;
default:
if (skip>0 && --skip==0)
{
delStart=start>=0?start:0;
if(delEnd==buf.length() && buf.charAt(delEnd-1)=='.')
delStart++;
}
}
// Do the delete
if (skip<=0 && delStart>=0 && delStart>=0)
{
buf.delete(delStart,delEnd);
delStart=delEnd=-1;
if (skip>0)
delEnd=end;
}
end=start--;
while (start>=0 && buf.charAt(start)!='/')
start--;
}
// Too many ..
if (skip>0)
return null;
// Do the delete
if (delEnd>=0)
buf.delete(delStart,delEnd);
return buf.toString();
}
/* ------------------------------------------------------------ */
/**
* @param uri URI
* @return True if the uri has a scheme
*/
public static boolean hasScheme(String uri)
{
for (int i=0;i<uri.length();i++)
{
char c=uri.charAt(i);
if (c==':')
return true;
if (!(c>='a'&&c<='z' ||
c>='A'&&c<='Z' ||
(i>0 &&(c>='0'&&c<='9' ||
c=='.' ||
c=='+' ||
c=='-'))
))
break;
}
return false;
}
}