com.liferay.portal.kernel.util.URLCodec.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.portal.kernel.util.URLCodec.java

Source

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.portal.kernel.util;

import com.liferay.petra.nio.CharsetDecoderUtil;
import com.liferay.petra.nio.CharsetEncoderUtil;
import com.liferay.petra.string.CharPool;
import com.liferay.petra.string.StringPool;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;

/**
 * @author Shuyang Zhou
 * @author Brian Wing Shun Chan
 */
public class URLCodec {

    public static String decodeURL(String encodedURLString) {
        return decodeURL(encodedURLString, StringPool.UTF8);
    }

    public static String decodeURL(String encodedURLString, String charsetName) {

        if (encodedURLString == null) {
            return null;
        }

        if (encodedURLString.length() == 0) {
            return StringPool.BLANK;
        }

        StringBuilder sb = null;

        CharsetDecoder charsetDecoder = null;

        for (int i = 0; i < encodedURLString.length(); i++) {
            char c = encodedURLString.charAt(i);

            if (c == CharPool.PERCENT) {
                ByteBuffer byteBuffer = _getEncodedByteBuffer(encodedURLString, i);

                if (charsetDecoder == null) {
                    charsetDecoder = CharsetDecoderUtil.getCharsetDecoder(charsetName);
                }

                CharBuffer charBuffer = null;

                try {
                    charBuffer = charsetDecoder.decode(byteBuffer);
                } catch (CharacterCodingException cce) {
                    _log.error(cce, cce);

                    return StringPool.BLANK;
                }

                if (sb == null) {
                    sb = new StringBuilder(encodedURLString.length());

                    if (i > 0) {
                        sb.append(encodedURLString, 0, i);
                    }
                }

                sb.append(charBuffer);

                i += byteBuffer.capacity() * 3 - 1;
            } else if (c == CharPool.PLUS) {
                if (sb == null) {
                    sb = new StringBuilder(encodedURLString.length());

                    if (i > 0) {
                        sb.append(encodedURLString, 0, i);
                    }
                }

                sb.append(CharPool.SPACE);
            } else if (sb != null) {
                sb.append(c);
            }
        }

        if (sb == null) {
            return encodedURLString;
        }

        return sb.toString();
    }

    public static String encodeURL(String rawURLString) {
        return encodeURL(rawURLString, StringPool.UTF8, false);
    }

    public static String encodeURL(String rawURLString, boolean escapeSpaces) {
        return encodeURL(rawURLString, StringPool.UTF8, escapeSpaces);
    }

    public static String encodeURL(String rawURLString, String charsetName, boolean escapeSpaces) {

        if (rawURLString == null) {
            return null;
        }

        if (rawURLString.isEmpty()) {
            return StringPool.BLANK;
        }

        CharsetEncoder charsetEncoder = null;
        char[] hexes = new char[2];
        int lastReplacementIndex = 0;
        StringBuilder sb = null;

        for (int i = 0; i < rawURLString.length(); i++) {
            char c = rawURLString.charAt(i);

            if ((c < 128) && _VALID_CHARS[c]) {
                continue;
            }

            if (sb == null) {
                sb = new StringBuilder(rawURLString.length() + 64);

                sb.append(rawURLString, 0, i);
            } else if (i > lastReplacementIndex) {
                sb.append(rawURLString, lastReplacementIndex, i);
            }

            if (c < 128) {
                char[] encodingReplacement = _ENCODING_REPLACEMENTS[c];

                if (encodingReplacement != null) {
                    if (!escapeSpaces && (c == CharPool.SPACE)) {
                        sb.append(CharPool.PLUS);
                    } else {
                        sb.append(encodingReplacement);
                    }

                    lastReplacementIndex = i + 1;

                    continue;
                }
            }

            CharBuffer charBuffer = _getRawCharBuffer(rawURLString, i, escapeSpaces);

            if (charsetEncoder == null) {
                charsetEncoder = CharsetEncoderUtil.getCharsetEncoder(charsetName);
            }

            i += charBuffer.length() - 1;

            lastReplacementIndex = i + 1;

            ByteBuffer byteBuffer = null;

            try {
                byteBuffer = charsetEncoder.encode(charBuffer);
            } catch (CharacterCodingException cce) {
                _log.error(cce, cce);

                return StringPool.BLANK;
            }

            for (int j = byteBuffer.position(); j < byteBuffer.limit(); j++) {
                sb.append(CharPool.PERCENT);

                sb.append(UnicodeFormatter.byteToHex(byteBuffer.get(), hexes, true));
            }
        }

        if (sb == null) {
            return rawURLString;
        }

        if (lastReplacementIndex < rawURLString.length()) {
            sb.append(rawURLString, lastReplacementIndex, rawURLString.length());
        }

        return sb.toString();
    }

    private static int _charToHex(char c) {
        if ((c >= CharPool.LOWER_CASE_A) && (c <= CharPool.LOWER_CASE_F)) {
            return c - CharPool.LOWER_CASE_A + 10;
        }

        if ((c >= CharPool.UPPER_CASE_A) && (c <= CharPool.UPPER_CASE_F)) {
            return c - CharPool.UPPER_CASE_A + 10;
        }

        if ((c >= CharPool.NUMBER_0) && (c <= CharPool.NUMBER_9)) {
            return c - CharPool.NUMBER_0;
        }

        throw new IllegalArgumentException(c + " is not a hex char");
    }

    private static ByteBuffer _getEncodedByteBuffer(String encodedString, int start) {

        int count = 1;

        for (int i = start + 3; i < encodedString.length(); i += 3) {
            if (encodedString.charAt(i) == CharPool.PERCENT) {
                count++;
            } else {
                break;
            }
        }

        if (encodedString.length() < (start + count * 3)) {
            throw new IllegalArgumentException("Invalid URL encoding " + encodedString);
        }

        ByteBuffer byteBuffer = ByteBuffer.allocate(count);

        for (int i = start; i < (start + count * 3); i += 3) {
            int high = _charToHex(encodedString.charAt(i + 1));
            int low = _charToHex(encodedString.charAt(i + 2));

            byteBuffer.put((byte) ((high << 4) + low));
        }

        byteBuffer.flip();

        return byteBuffer;
    }

    private static CharBuffer _getRawCharBuffer(String rawString, int start, boolean escapeSpaces) {

        int count = 0;

        for (int i = start; i < rawString.length(); i++) {
            char rawChar = rawString.charAt(i);

            if (((rawChar >= 128) || !_VALID_CHARS[rawChar]) && (escapeSpaces || (rawChar != CharPool.SPACE))) {

                count++;

                if (Character.isHighSurrogate(rawChar) && ((i + 1) < rawString.length())
                        && Character.isLowSurrogate(rawString.charAt(i + 1))) {

                    i++;
                    count++;
                }
            } else {
                break;
            }
        }

        return CharBuffer.wrap(rawString, start, start + count);
    }

    private static final char[][] _ENCODING_REPLACEMENTS = new char[128][];

    private static final boolean[] _VALID_CHARS = new boolean[128];

    private static final Log _log = LogFactoryUtil.getLog(URLCodec.class);

    static {
        _ENCODING_REPLACEMENTS[CharPool.AMPERSAND] = "%26".toCharArray();
        _ENCODING_REPLACEMENTS[CharPool.COLON] = "%3A".toCharArray();
        _ENCODING_REPLACEMENTS[CharPool.EQUAL] = "%3D".toCharArray();
        _ENCODING_REPLACEMENTS[CharPool.PERCENT] = "%25".toCharArray();
        _ENCODING_REPLACEMENTS[CharPool.PLUS] = "%2B".toCharArray();
        _ENCODING_REPLACEMENTS[CharPool.QUESTION] = "%3F".toCharArray();
        _ENCODING_REPLACEMENTS[CharPool.SLASH] = "%2F".toCharArray();
        _ENCODING_REPLACEMENTS[CharPool.SPACE] = "%20".toCharArray();

        for (int i = 'a'; i <= 'z'; i++) {
            _VALID_CHARS[i] = true;
        }

        for (int i = 'A'; i <= 'Z'; i++) {
            _VALID_CHARS[i] = true;
        }

        for (int i = '0'; i <= '9'; i++) {
            _VALID_CHARS[i] = true;
        }

        _VALID_CHARS['-'] = true;
        _VALID_CHARS['_'] = true;
        _VALID_CHARS['.'] = true;
        _VALID_CHARS['*'] = true;
    }

}