public String encode(final String s, final String charsetName)
{
boolean needToChange = false;
StringBuilder out = new StringBuilder(s.length());
Charset charset;
CharArrayWriter charArrayWriter = new CharArrayWriter();
Args.notNull(charsetName, "charsetName");
try
{
charset = Charset.forName(charsetName);
}
catch (IllegalCharsetNameException e)
{
throw new RuntimeException(new UnsupportedEncodingException(charsetName));
}
catch (UnsupportedCharsetException e)
{
throw new RuntimeException(new UnsupportedEncodingException(charsetName));
}
boolean stopEncoding = false;
for (int i = 0; i < s.length();)
{
int c = s.charAt(i);
if ((stopEncoding == false) && (c == stopChar))
{
stopEncoding = true;
}
// System.out.println("Examining character: " + c);
if ((stopEncoding == true) || dontNeedEncoding.get(c))
{
if (c == ' ')
{
c = '+';
needToChange = true;
}
// System.out.println("Storing: " + c);
out.append((char)c);
i++;
}
else
{
// convert to external encoding before hex conversion
do
{
charArrayWriter.write(c);
/*
* If this character represents the start of a Unicode surrogate pair, then pass
* in two characters. It's not clear what should be done if a bytes reserved in
* the surrogate pairs range occurs outside of a legal surrogate pair. For now,
* just treat it as if it were any other character.
*/
if ((c >= 0xD800) && (c <= 0xDBFF))
{
/*
* System.out.println(Integer.toHexString(c) + " is high surrogate");
*/
if ((i + 1) < s.length())
{
int d = s.charAt(i + 1);
/*
* System.out.println("\tExamining " + Integer.toHexString(d));
*/
if ((d >= 0xDC00) && (d <= 0xDFFF))
{
/*
* System.out.println("\t" + Integer.toHexString(d) + " is low
* surrogate");
*/
charArrayWriter.write(d);
i++;
}
}
}
i++;
}
while ((i < s.length()) && !dontNeedEncoding.get((c = s.charAt(i))));
charArrayWriter.flush();
String str = new String(charArrayWriter.toCharArray());
byte[] ba;
try
{
ba = str.getBytes(charset.name());
}
catch (UnsupportedEncodingException e)
{
throw new RuntimeException(e);
}
for (byte b : ba)
{
out.append('%');
char ch = Character.forDigit((b >> 4) & 0xF, 16);
// converting to use uppercase letter as part of
// the hex value if ch is a letter.
if (Character.isLetter(ch))
{
ch -= caseDiff;
}
out.append(ch);
ch = Character.forDigit(b & 0xF, 16);
if (Character.isLetter(ch))
{
ch -= caseDiff;
}
out.append(ch);
}
charArrayWriter.reset();
needToChange = true;
}
}
return (needToChange ? out.toString() : s);