|
16 | 16 |
|
17 | 17 | package org.springframework.util;
|
18 | 18 |
|
19 |
| -import java.io.ByteArrayOutputStream; |
20 | 19 | import java.nio.charset.Charset;
|
21 | 20 | import java.util.ArrayDeque;
|
22 | 21 | import java.util.ArrayList;
|
|
25 | 24 | import java.util.Collections;
|
26 | 25 | import java.util.Deque;
|
27 | 26 | import java.util.Enumeration;
|
| 27 | +import java.util.HexFormat; |
28 | 28 | import java.util.Iterator;
|
29 | 29 | import java.util.LinkedHashSet;
|
30 | 30 | import java.util.List;
|
@@ -816,38 +816,50 @@ public static boolean pathEquals(String path1, String path2) {
|
816 | 816 | * @see java.net.URLDecoder#decode(String, String)
|
817 | 817 | */
|
818 | 818 | public static String uriDecode(String source, Charset charset) {
|
| 819 | + Assert.notNull(charset, "Charset must not be null"); |
819 | 820 | int length = source.length();
|
820 | 821 | if (length == 0) {
|
821 | 822 | return source;
|
822 | 823 | }
|
823 |
| - Assert.notNull(charset, "Charset must not be null"); |
824 | 824 |
|
825 |
| - ByteArrayOutputStream baos = new ByteArrayOutputStream(length); |
| 825 | + StringBuilder output = new StringBuilder(length); |
826 | 826 | boolean changed = false;
|
827 |
| - for (int i = 0; i < length; i++) { |
828 |
| - int ch = source.charAt(i); |
| 827 | + byte[] bytes = null; |
| 828 | + int i = 0; |
| 829 | + while (i < length) { |
| 830 | + char ch = source.charAt(i); |
829 | 831 | if (ch == '%') {
|
830 |
| - if (i + 2 < length) { |
831 |
| - char hex1 = source.charAt(i + 1); |
832 |
| - char hex2 = source.charAt(i + 2); |
833 |
| - int u = Character.digit(hex1, 16); |
834 |
| - int l = Character.digit(hex2, 16); |
835 |
| - if (u == -1 || l == -1) { |
836 |
| - throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\""); |
| 832 | + try { |
| 833 | + if (bytes == null) { |
| 834 | + bytes = new byte[(length - i) / 3]; |
| 835 | + } |
| 836 | + |
| 837 | + int pos = 0; |
| 838 | + while (i + 2 < length && ch == '%') { |
| 839 | + bytes[pos++] = (byte) HexFormat.fromHexDigits(source, i + 1, i + 3); |
| 840 | + i += 3; |
| 841 | + if (i < length) { |
| 842 | + ch = source.charAt(i); |
| 843 | + } |
837 | 844 | }
|
838 |
| - baos.write((char) ((u << 4) + l)); |
839 |
| - i += 2; |
| 845 | + |
| 846 | + if (i < length && ch == '%') { |
| 847 | + throw new IllegalArgumentException("Incomplete trailing escape (%) pattern"); |
| 848 | + } |
| 849 | + |
| 850 | + output.append(new String(bytes, 0, pos, charset)); |
840 | 851 | changed = true;
|
841 | 852 | }
|
842 |
| - else { |
| 853 | + catch (NumberFormatException ex) { |
843 | 854 | throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\"");
|
844 | 855 | }
|
845 | 856 | }
|
846 | 857 | else {
|
847 |
| - baos.write(ch); |
| 858 | + output.append(ch); |
| 859 | + i++; |
848 | 860 | }
|
849 | 861 | }
|
850 |
| - return (changed ? StreamUtils.copyToString(baos, charset) : source); |
| 862 | + return (changed ? output.toString() : source); |
851 | 863 | }
|
852 | 864 |
|
853 | 865 | /**
|
|
0 commit comments