blob: 3200a9fd354ec76848c96ce63a8924f7e778bddc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* James D Miles (IBM Corp.) - bug 191368, Policy URL doesn't support UTF-8 characters
*******************************************************************************/
package org.eclipse.update.internal.core;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.StringTokenizer;
import org.eclipse.core.runtime.Assert;
/**
* Encodes a <code>URL</code> into an <code>ASCII</code> readable
* <code>URL</code> that is safe for transport. Encoded
* <code>URL</code>s can be decoded using the <code>URLDecoder</code>.
*
* @see URLDecoder
*/
public final class URLEncoder {
/**
* Prevents instances from being created.
*/
private URLEncoder() {
}
/**
* Encodes the given file and reference parts of a <code>URL</code> into
* an <code>ASCII</code> readable <code>String</code> that is safe for
* transport. Returns the result.
*
* @return the result of encoding the given file and reference parts of
* a <code>URL</code> into an <code>ASCII</code> readable
* <code>String</code> that is safe for transport
*/
public static String encode(String file, String query, String ref) {
StringBuffer buf = new StringBuffer();
StringTokenizer tokenizer = new StringTokenizer(file, "/", true); //$NON-NLS-1$
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
if (token.equals("/")) { //$NON-NLS-1$
buf.append(token);
} else {
buf.append(encodeSegment(token));
}
}
if (query != null){
buf.append('?');
buf.append(query);
}
if (ref != null) {
buf.append('#');
buf.append(encodeSegment(ref));
}
return buf.toString();
}
/**
* Encodes the given <code>URL</code> into an <code>ASCII</code>
* readable <code>URL</code> that is safe for transport. Returns the
* result.
*
* @return the result of encoding the given <code>URL</code> into an
* <code>ASCII</code> readable <code>URL</code> that is safe for
* transport
*/
public static URL encode(URL url) throws MalformedURLException {
// encode the path not the file as the URL may contain a query
String file = url.getPath();
String query = url.getQuery();
String ref = url.getRef();
String auth = url.getAuthority();
String host = url.getHost();
int port = url.getPort();
String userinfo = url.getUserInfo();
// do not encode if there is an authority, such as in
// ftp://user:password@host:port/path
// because the URL constructor does not allow it
URL result = url;
if (auth == null || auth.equals("") || userinfo == null) // $NON-NLS-1$ $NON-NLS-2$ //$NON-NLS-1$
result = new URL(url.getProtocol(), host, port, encode(file, query, ref));
return result;
}
private static String encodeSegment(String segment) {
// if we find a '%' in the string, consider the URL to be already encoded
if (segment.indexOf('%')!=-1) return segment;
StringBuffer result = new StringBuffer(segment.length());
for (int i = 0; i < segment.length(); ++i) {
char c = segment.charAt(i);
if (mustEncode(c)) {
byte[] bytes = null;
try {
bytes = new Character(c).toString().getBytes("UTF8"); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
Assert.isTrue(false, e.getMessage());
}
for (int j = 0; j < bytes.length; ++j) {
result.append('%');
result.append(Integer.toHexString((bytes[j] >> 4) & 0x0F));
result.append(Integer.toHexString(bytes[j] & 0x0F));
}
} else {
result.append(c);
}
}
return result.toString();
}
private static boolean mustEncode(char c) {
if (c >= 'a' && c <= 'z') {
return false;
}
if (c >= 'A' && c <= 'Z') {
return false;
}
if (c >= '0' && c <= '9') {
return false;
}
if (c >= '\'' && c <= '.') {
return false;
}
if (c == '!' || c == '$' || c == '_' || c == '[' || c == ']') {
return false;
}
// needed otherwise file:///c:/file/ becomes file:///C%3a/file/
if (c ==':'){
return false;
}
return true;
}
}