Skip to content

Commit fc6bb34

Browse files
PatilShreyastschuchortdev
authored andcommitted
#364 | Add utility for encoding path string
1 parent 2524a67 commit fc6bb34

File tree

1 file changed

+79
-0
lines changed

1 file changed

+79
-0
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package com.tschuchort.compiletesting
2+
3+
import java.io.ByteArrayOutputStream
4+
import java.nio.charset.StandardCharsets
5+
6+
/**
7+
* Encode the given URI [path] with UTF_8 encoding
8+
*/
9+
fun encodePath(path: String): String {
10+
if (path.isBlank()) {
11+
return path
12+
}
13+
val bytes = path.encodeToByteArray()
14+
var alreadyEncoded = true
15+
for (b in bytes) {
16+
if (!isValidEncodedChar(b.toInt())) {
17+
alreadyEncoded = false
18+
break
19+
}
20+
}
21+
if (alreadyEncoded) {
22+
return path
23+
}
24+
25+
val baos = ByteArrayOutputStream(bytes.size)
26+
for (b in bytes) {
27+
val byte = b.toInt()
28+
if (isValidEncodedChar(byte)) {
29+
baos.write(byte)
30+
} else {
31+
baos.write('%'.code)
32+
val hex1 = Character.forDigit(/* digit = */ b.toInt() shr 4 and 0xF, /* radix = */ 16).uppercaseChar()
33+
val hex2 = Character.forDigit(/* digit = */ b.toInt() and 0xF, /* radix = */ 16).uppercaseChar()
34+
baos.write(hex1.code)
35+
baos.write(hex2.code)
36+
}
37+
}
38+
return baos.toString(StandardCharsets.UTF_8.toString())
39+
}
40+
41+
/**
42+
* Checks whether input char [c] is valid and already an encoded character or not.
43+
*/
44+
fun isValidEncodedChar(c: Int): Boolean {
45+
return isPchar(c) || '/'.code == c
46+
}
47+
48+
/**
49+
* Indicates whether the given character is in the {@code pchar} set.
50+
* @see <a href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
51+
*/
52+
fun isPchar(c: Int): Boolean {
53+
return (isUnreserved(c) || isSubDelimiter(c) || ':'.code == c || '@'.code == c)
54+
}
55+
56+
/**
57+
* Indicates whether the given character is in the `sub-delims` set.
58+
* @see <a href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
59+
*/
60+
fun isSubDelimiter(c: Int): Boolean {
61+
return '!'.code == c || '$'.code == c || '&'.code == c || '\''.code == c || '('.code == c || ')'.code == c || '*'.code == c || '+'.code == c || ','.code == c || ';'.code == c || '='.code == c
62+
}
63+
64+
/**
65+
* Indicates whether the given character is in the `unreserved` set.
66+
* @see <a href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
67+
*/
68+
fun isUnreserved(c: Int): Boolean {
69+
return isAlpha(c) || Character.isDigit(c) || '-'.code == c || '.'.code == c || '_'.code == c || '~'.code == c
70+
}
71+
72+
/**
73+
* Indicates whether the given character is in the `ALPHA` set.
74+
* @see <a href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
75+
*/
76+
fun isAlpha(c: Int): Boolean {
77+
return c >= 'a'.code && c <= 'z'.code || c >= 'A'.code && c <= 'Z'.code
78+
}
79+

0 commit comments

Comments
 (0)