+++ /dev/null
-package de.halbekunst.juplo.utils;
-
-import java.nio.charset.Charset;
-
-/**
- * This class performes percent-encoding/-decoding like described in RFC 3986.
- * <p>
- * Complete URI's are not handled by this implementation.
- * That is done best with the original {@linkplain java.net.URI}-class from core Java.
- * The purpose of this class is to have a simple tool to encode/decode the
- * inner parts of an URI, like a segment of the URI-path (the part between two
- * forward slashes) or a name or value segment of the query, where all reserved
- * characters must be encoded/decoded.
- *
- * @author kai
- */
-public class PercentCodec {
- private final Charset charset;
-
-
- public PercentCodec(String encoding) {
- charset = Charset.forName(encoding);
- }
-
-
- public String encode(CharSequence in) {
- StringBuilder out = new StringBuilder();
- int i = 0;
- int length = in.length();
- while (i < length) {
- int codePoint = Character.codePointAt(in, i);
- i += Character.charCount(codePoint);
- switch (codePoint) {
- case 'a':
- case 'A':
- case 'b':
- case 'B':
- case 'c':
- case 'C':
- case 'd':
- case 'D':
- case 'e':
- case 'E':
- case 'f':
- case 'F':
- case 'g':
- case 'G':
- case 'h':
- case 'H':
- case 'i':
- case 'I':
- case 'j':
- case 'J':
- case 'k':
- case 'K':
- case 'l':
- case 'L':
- case 'm':
- case 'M':
- case 'n':
- case 'N':
- case 'o':
- case 'O':
- case 'p':
- case 'P':
- case 'q':
- case 'Q':
- case 'r':
- case 'R':
- case 's':
- case 'S':
- case 't':
- case 'T':
- case 'u':
- case 'U':
- case 'v':
- case 'V':
- case 'w':
- case 'W':
- case 'x':
- case 'X':
- case 'y':
- case 'Y':
- case 'z':
- case 'Z':
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '-':
- case '_':
- case '.':
- case '~':
- /**
- * Unreserved characters can (and should!) stay unchanged!
- * (See {@link http://en.wikipedia.org/wiki/Percent-encoding#Types_of_URI_characters})
- */
- out.append(Character.toChars(codePoint));
- break;
- default:
- /**
- * All other characters are reserved or special characters and,
- * hence, must be encoded!
- */
- String encoded = new String(Character.toChars(codePoint));
- byte[] bytes = encoded.getBytes(charset);
- for (int j = 0; j < bytes.length; j++) {
- out.append('%');
- out.append(Character.forDigit((bytes[j] >> 4) & 0xF, 16));
- out.append(Character.forDigit((bytes[j]) & 0xF, 16));
- }
- }
- }
- return out.toString();
- }
-
- public String decode(CharSequence in) {
- StringBuilder out = new StringBuilder();
- int i = 0;
- int length = in.length();
- while (i < length) {
- char c = in.charAt(i);
- if (c != '%') {
- out.append(c);
- i++;
- }
- else {
- byte[] bytes = new byte[length-i/3];
- int pos = 0;
- while (i+2 < length && in.charAt(i) == '%' ) {
- int b = 0;
- switch (in.charAt(i+1)) {
- case '0': break;
- case '1': b = 16*1; break;
- case '2': b = 16*2; break;
- case '3': b = 16*3; break;
- case '4': b = 16*4; break;
- case '5': b = 16*5; break;
- case '6': b = 16*6; break;
- case '7': b = 16*7; break;
- case '8': b = 16*8; break;
- case '9': b = 16*9; break;
- case 'a':
- case 'A': b = 16*10; break;
- case 'b':
- case 'B': b = 16*11; break;
- case 'c':
- case 'C': b = 16*12; break;
- case 'd':
- case 'D': b = 16*13; break;
- case 'e':
- case 'E': b = 16*14; break;
- case 'f':
- case 'F': b = 16*15; break;
- default: throw new IllegalArgumentException("Illegal escape-sequence: %" + in.subSequence(i, i+3));
- }
- switch (in.charAt(i+2)) {
- case '0': break;
- case '1': b += 1; break;
- case '2': b += 2; break;
- case '3': b += 3; break;
- case '4': b += 4; break;
- case '5': b += 5; break;
- case '6': b += 6; break;
- case '7': b += 7; break;
- case '8': b += 8; break;
- case '9': b += 9; break;
- case 'a':
- case 'A': b += 10; break;
- case 'b':
- case 'B': b += 11; break;
- case 'c':
- case 'C': b += 12; break;
- case 'd':
- case 'D': b += 13; break;
- case 'e':
- case 'E': b += 14; break;
- case 'f':
- case 'F': b += 15; break;
- default: throw new IllegalArgumentException("Illegal escape-sequence: %" + in.subSequence(i, i+3));
- }
- bytes[pos++] = (byte)b;
- i += 3;
- }
- out.append(new String(bytes, 0, pos, charset));
- if (i < length && in.charAt(i) == '%')
- throw new IllegalArgumentException("Incomplete escape-sequence: %" + in.subSequence(i, length));
- }
- }
- return out.toString();
- }
-}