/*
* © Copyright IBM Corp. 2012
*
* 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 com.ibm.commons.runtime.util;
import java.io.*;
import java.util.BitSet;
/**
* URLEncoder does not work properly when encoding UTL.
* This class uses the same strategy than the JSF RI HtmlUtils method
*
* @author priand
*/
public class URLEncoding {
private static final BitSet DONT_ENCODE_SET = new BitSet(256);
// See: http://www.ietf.org/rfc/rfc2396.txt
// We're not fully along for that ride either, but we do encode
// ' ' as '%20', and don't bother encoding '~' or '/'
static {
for (int i = 'a'; i <= 'z'; i++) {
DONT_ENCODE_SET.set(i);
}
for (int i = 'A'; i <= 'Z'; i++) {
DONT_ENCODE_SET.set(i);
}
for (int i = '0'; i <= '9'; i++) {
DONT_ENCODE_SET.set(i);
}
// Don't encode '%' - we don't want to double encode anything.
DONT_ENCODE_SET.set('%');
// Ditto for '+', which is an encoded space
DONT_ENCODE_SET.set('+');
DONT_ENCODE_SET.set('#');
DONT_ENCODE_SET.set('&');
DONT_ENCODE_SET.set('=');
DONT_ENCODE_SET.set('-');
DONT_ENCODE_SET.set('_');
DONT_ENCODE_SET.set('.');
DONT_ENCODE_SET.set('*');
DONT_ENCODE_SET.set('~');
DONT_ENCODE_SET.set('/');
DONT_ENCODE_SET.set('\'');
DONT_ENCODE_SET.set('!');
DONT_ENCODE_SET.set('(');
DONT_ENCODE_SET.set(')');
}
public static String encodeURIString(String text, String encoding, int start, boolean isQueryString) throws IOException, UnsupportedEncodingException {
StringBuilder b = new StringBuilder();
char[] cArray = null;
int length = text.length();
for (int i = start; i < length; i++) {
char ch = text.charAt(i);
// PHIL: we should not replace the & by & in this case as we are not
// storing the URL within the HTML
if (DONT_ENCODE_SET.get(ch)) {
b.append(ch);
} else if(ch==':' && !isQueryString) {
// Emit the : as it is generally part of the protocol (http://)
b.append(ch);
} else if(ch=='?' && !isQueryString) {
// Emit the start of the query string, as expected
b.append(ch);
isQueryString = true;
} else {
// Is there a faster way for getting the bytes?
// It looks like StringCoding class is an internal implementation
if(cArray==null) {
cArray = new char[1];
}
cArray[0] = ch;
String s = new String(cArray);
byte[] ba = s.getBytes("UTF-8"); // $NON-NLS-1$
for (int j = 0; j < ba.length; j++) {
writeURIDoubleHex(b, ba[j] + 256);
}
}
}
return b.toString();
}
static private void writeURIDoubleHex(StringBuilder b, int i) throws IOException {
b.append('%');
b.append(intToHex((i >> 4) & 0x0F));
b.append(intToHex(i & 0x0F));
}
static private char intToHex(int i) {
if (i < 10) {
return ((char) ('0' + i));
} else {
return ((char) ('A' + (i - 10)));
}
}
}