Fix url_decode with mixed percent-encoding/Unicode strings. Treat Unix drive names as UTF-8 encoded.

This commit is contained in:
bruvzg 2021-04-30 21:22:39 +03:00
parent 28f56e2cbf
commit b6a21f85a7
No known key found for this signature in database
GPG Key ID: 009E1BFE42239B95
3 changed files with 28 additions and 14 deletions

View File

@ -3784,27 +3784,28 @@ String String::uri_encode() const {
} }
String String::uri_decode() const { String String::uri_decode() const {
String res; CharString src = utf8();
for (int i = 0; i < length(); ++i) { CharString res;
if (unicode_at(i) == '%' && i + 2 < length()) { for (int i = 0; i < src.length(); ++i) {
char32_t ord1 = unicode_at(i + 1); if (src[i] == '%' && i + 2 < src.length()) {
char ord1 = src[i + 1];
if ((ord1 >= '0' && ord1 <= '9') || (ord1 >= 'A' && ord1 <= 'Z')) { if ((ord1 >= '0' && ord1 <= '9') || (ord1 >= 'A' && ord1 <= 'Z')) {
char32_t ord2 = unicode_at(i + 2); char ord2 = src[i + 2];
if ((ord2 >= '0' && ord2 <= '9') || (ord2 >= 'A' && ord2 <= 'Z')) { if ((ord2 >= '0' && ord2 <= '9') || (ord2 >= 'A' && ord2 <= 'Z')) {
char bytes[3] = { (char)ord1, (char)ord2, 0 }; char bytes[3] = { (char)ord1, (char)ord2, 0 };
res += (char)strtol(bytes, nullptr, 16); res += (char)strtol(bytes, nullptr, 16);
i += 2; i += 2;
} }
} else { } else {
res += unicode_at(i); res += src[i];
} }
} else if (unicode_at(i) == '+') { } else if (src[i] == '+') {
res += ' '; res += ' ';
} else { } else {
res += unicode_at(i); res += src[i];
} }
} }
return String::utf8(res.ascii()); return String::utf8(res);
} }
String String::c_unescape() const { String String::c_unescape() const {

View File

@ -226,8 +226,9 @@ static void _get_drives(List<String> *list) {
while (getmntent_r(mtab, &mnt, strings, sizeof(strings))) { while (getmntent_r(mtab, &mnt, strings, sizeof(strings))) {
if (mnt.mnt_dir != nullptr && _filter_drive(&mnt)) { if (mnt.mnt_dir != nullptr && _filter_drive(&mnt)) {
// Avoid duplicates // Avoid duplicates
if (!list->find(mnt.mnt_dir)) { String name = String::utf8(mnt.mnt_dir);
list->push_back(mnt.mnt_dir); if (!list->find(name)) {
list->push_back(name);
} }
} }
} }
@ -240,8 +241,9 @@ static void _get_drives(List<String> *list) {
const char *home = getenv("HOME"); const char *home = getenv("HOME");
if (home) { if (home) {
// Only add if it's not a duplicate // Only add if it's not a duplicate
if (!list->find(home)) { String home_name = String::utf8(home);
list->push_back(home); if (!list->find(home_name)) {
list->push_back(home_name);
} }
// Check $HOME/.config/gtk-3.0/bookmarks // Check $HOME/.config/gtk-3.0/bookmarks
@ -254,7 +256,7 @@ static void _get_drives(List<String> *list) {
// Parse only file:// links // Parse only file:// links
if (strncmp(string, "file://", 7) == 0) { if (strncmp(string, "file://", 7) == 0) {
// Strip any unwanted edges on the strings and push_back if it's not a duplicate // Strip any unwanted edges on the strings and push_back if it's not a duplicate
String fpath = String(string + 7).strip_edges().split_spaces()[0].uri_decode(); String fpath = String::utf8(string + 7).strip_edges().split_spaces()[0].uri_decode();
if (!list->find(fpath)) { if (!list->find(fpath)) {
list->push_back(fpath); list->push_back(fpath);
} }

View File

@ -1156,6 +1156,17 @@ TEST_CASE("[String] uri_encode/unescape") {
String s = "Godot Engine:'docs'"; String s = "Godot Engine:'docs'";
String t = "Godot%20Engine%3A%27docs%27"; String t = "Godot%20Engine%3A%27docs%27";
String x1 = "T%C4%93%C5%A1t";
static const uint8_t u8str[] = { 0x54, 0xC4, 0x93, 0xC5, 0xA1, 0x74, 0x00 };
String x2 = String::utf8((const char *)u8str);
String x3 = U"Tēšt";
CHECK(x1.uri_decode() == x2);
CHECK(x1.uri_decode() == x3);
CHECK((x1 + x3).uri_decode() == (x2 + x3)); // Mixed unicode and URL encoded string, e.g. GTK+ bookmark.
CHECK(x2.uri_encode() == x1);
CHECK(x3.uri_encode() == x1);
CHECK(s.uri_encode() == t); CHECK(s.uri_encode() == t);
CHECK(t.uri_decode() == s); CHECK(t.uri_decode() == s);
} }