public static String decode(String uri) {
    	if(logger.isDebugEnabled()) {
    		logger.debug("uri to decode " + uri);
    	}
    	if(uri == null) {
    		// fix by Hauke D. Issue 410
//    		throw new NullPointerException("uri cannot be null !");
    		return null;
    	}
        
        //optimization for uri with no escaped chars
        //fixes https://github.com/RestComm/sip-servlets/issues/124
        if (uri.indexOf(UTF8_ESCAPE_CHAR) < 0) {
            return uri;
        }
        
        StringBuffer translatedUri = new StringBuffer(uri.length());
        byte[] encodedchars = new byte[uri.length() / 3];
        int i = 0;
        int length = uri.length();
        int encodedcharsLength = 0;
        while (i < length) {
            if (uri.charAt(i) == UTF8_ESCAPE_CHAR) {
                //we must process all consecutive %-encoded characters in one go, because they represent
                //an UTF-8 encoded string, and in UTF-8 one character can be encoded as multiple bytes
                while (i < length && uri.charAt(i) == UTF8_ESCAPE_CHAR) {
                    if (i + 2 < length) {
                        try {
                            byte x = (byte)Integer.parseInt(uri.substring(i + 1, i + 3), 16);
                            encodedchars[encodedcharsLength] = x;
                        } catch (NumberFormatException e) {
                        	// do not throw exception, a % could be part of a IPv6 address and still be valid
//                            throw new IllegalArgumentException("Illegal hex characters in pattern %" + uri.substring(i + 1, i + 3));
                        }
                        encodedcharsLength++;
                        i += 3;
                    } else {
                    	// do not throw exception, a % could be part of a IPv6 address and still be valid
//                        throw new IllegalArgumentException("% character should be followed by 2 hexadecimal characters.");
                    }
                }
                try {
                    String translatedPart = new String(encodedchars, 0, encodedcharsLength, UTF_8);
                    translatedUri.append(translatedPart);
                } catch (UnsupportedEncodingException e) {
                    //the situation that UTF-8 is not supported is quite theoretical, so throw a runtime exception
                    throw new IllegalArgumentException("Problem in decodePath: UTF-8 encoding not supported.");
                }
                encodedcharsLength = 0;
            } else {
                //a normal character
                translatedUri.append(uri.charAt(i));
                i++;
            }
        }
        if(logger.isDebugEnabled()) {
    		logger.debug("decoded uri " + translatedUri);
    	}
        return translatedUri.toString();
    }
public static String decode ( String uri ) { if ( logger . isDebugEnabled ( ) ) { logger . debug ( "uri to decode " + uri ) ; } if ( uri == null ) { return null ; } if ( uri . indexOf ( UTF8_ESCAPE_CHAR ) < 0 ) { return uri ; } StringBuffer translatedUri = new StringBuffer ( uri . length ( ) ) ; byte [ ] encodedchars = new byte [ uri . length ( ) / 3 ] ; int i = 0 ; int length = uri . length ( ) ; int encodedcharsLength = 0 ; while ( i < length ) { if ( uri . charAt ( i ) == UTF8_ESCAPE_CHAR ) { while ( i < length && uri . charAt ( i ) == UTF8_ESCAPE_CHAR ) { if ( i + 2 < length ) { try { byte x = ( byte ) Integer . parseInt ( uri . substring ( i + 1 , i + 3 ) , 16 ) ; encodedchars [ encodedcharsLength ] = x ; } catch ( NumberFormatException e ) { } encodedcharsLength ++ ; i += 3 ; } else { } } try { String translatedPart = new String ( encodedchars , 0 , encodedcharsLength , UTF_8 ) ; translatedUri . append ( translatedPart ) ; } catch ( UnsupportedEncodingException e ) { throw new IllegalArgumentException ( "Problem in decodePath: UTF-8 encoding not supported." ) ; } encodedcharsLength = 0 ; } else { translatedUri . append ( uri . charAt ( i ) ) ; i ++ ; } } if ( logger . isDebugEnabled ( ) ) { logger . debug ( "decoded uri " + translatedUri ) ; } return translatedUri . toString ( ) ; }
Decode a path.

<p>Interprets %XX (where XX is hexadecimal number) as UTF-8 encoded bytes.
<p>The validity of the input path is not checked (i.e. characters that
were not encoded will not be reported as errors).
<p>This method differs from URLDecoder.decode in that it always uses UTF-8
(while URLDecoder uses the platform default encoding, often ISO-8859-1),
and doesn't translate + characters to spaces.

@param uri the path to decode
@return the decoded path