private static String percentDecode ( String encoded ) { Preconditions . checkArgument ( ascii ( ) . matchesAllOf ( encoded ) , "string must be ASCII" ) ; ByteArrayOutputStream out = new ByteArrayOutputStream ( encoded . length ( ) ) ; for ( int i = 0 ; i < encoded . length ( ) ; i ++ ) { char c = encoded . charAt ( i ) ; if ( c == ' ' ) { Preconditions . checkArgument ( i + 2 < encoded . length ( ) , "percent encoded value is truncated" ) ; int high = Character . digit ( encoded . charAt ( i + 1 ) , 16 ) ; int low = Character . digit ( encoded . charAt ( i + 2 ) , 16 ) ; Preconditions . checkArgument ( high != - 1 && low != - 1 , "percent encoded value is not a valid hex string: " , encoded . substring ( i , i + 2 ) ) ; int value = ( high << 4 ) | ( low ) ; out . write ( value ) ; i += 2 ; } else { out . write ( ( int ) c ) ; } } try { return UTF_8 . newDecoder ( ) . onMalformedInput ( CodingErrorAction . REPORT ) . decode ( ByteBuffer . wrap ( out . toByteArray ( ) ) ) . toString ( ) ; } catch ( CharacterCodingException e ) { throw new IllegalArgumentException ( "input does not represent a proper UTF8-encoded string" ) ; } }
input must be an ASCII string representing a percent - encoded UTF - 8 byte sequence