/* * Perform an unescape operation based on char[]. */ static void unescape( final char[] text, final int offset, final int len, final Writer writer, final UriEscapeType escapeType, final String encoding) throws IOException { if (text == null) { return; } final int max = (offset + len); int readOffset = offset; for (int i = offset; i < max; i++) { final char c = text[i]; /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX && (c != '+' || !escapeType.canPlusEscapeWhitespace())) { continue; } /* * At this point we know for sure we will need some kind of unescape, so we * can increase the offset copy all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } /* * Deal with possible '+'-escaped whitespace (application/x-www-form-urlencoded) */ if (c == '+') { // if we reached this point with c == '+', it's escaping a whitespace writer.write(' '); readOffset = i + 1; continue; } /* * ESCAPE PROCESS * -------------- * If there are more than one percent-encoded/escaped sequences together, we will * need to unescape them all at once (because they might be bytes --up to 4-- of * the same char). */ // Max possible size will be the remaining amount of chars / 3 final byte[] bytes = new byte[(max - i) / 3]; char aheadC = c; int pos = 0; while (((i + 2) < max) && aheadC == ESCAPE_PREFIX) { bytes[pos++] = parseHexa(text[i + 1], text[i + 2]); i += 3; if (i < max) { aheadC = text[i]; } } if (i < max && aheadC == ESCAPE_PREFIX) { // Incomplete escape sequence! throw new IllegalArgumentException("Incomplete escaping sequence in input"); } try { writer.write(new String(bytes, 0, pos, encoding)); } catch (final UnsupportedEncodingException e) { throw new IllegalArgumentException( "Exception while escaping URI: Bad encoding '" + encoding + "'", e); } readOffset = i; } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no unescape was actually needed. Otherwise * append the remaining escaped text and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } }
/* * Perform an escape operation, based on char[], according to the specified type */ static void escape( final char[] text, final int offset, final int len, final Writer writer, final UriEscapeType escapeType, final String encoding) throws IOException { if (text == null || text.length == 0) { return; } final int max = (offset + len); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be alphabetic, and we won't need to do anything at * all for them. No need to use the complete UriEscapeType check system at all. */ if (UriEscapeType.isAlpha(codepoint)) { continue; } /* * Check whether the character is allowed or not */ if (escapeType.isAllowed(codepoint)) { continue; } /* * At this point we know for sure we will need some kind of escape, so we * can write all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single // codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Peform the real escape * * ----------------------------------------------------------------------------------------- */ final byte[] charAsBytes; try { charAsBytes = new String(Character.toChars(codepoint)).getBytes(encoding); } catch (final UnsupportedEncodingException e) { throw new IllegalArgumentException( "Exception while escaping URI: Bad encoding '" + encoding + "'", e); } for (final byte b : charAsBytes) { writer.write('%'); writer.write(printHexa(b)); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } }