QStorageInfo/Linux: decode the names encoded by udev in-place

This function is only called with the name of a file coming from
QFileInfo::fileName() so it's usually already detached anyway. And if
there's nothing to decode, pass the string through without even
attempting to modify it.

Pick-to: 6.6
Change-Id: I9d43e5b91eb142d6945cfffd1787651437074d35
Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
This commit is contained in:
Thiago Macieira 2023-09-22 19:08:42 -07:00
parent 4107e4d8ca
commit 39843b65f4

View File

@ -8,6 +8,7 @@
#include "qdiriterator.h" #include "qdiriterator.h"
#include <private/qcore_unix_p.h> #include <private/qcore_unix_p.h>
#include <private/qtools_p.h>
#if defined(Q_OS_ANDROID) #if defined(Q_OS_ANDROID)
# include <sys/mount.h> # include <sys/mount.h>
@ -35,27 +36,39 @@ using namespace Qt::StringLiterals;
// udev encodes the labels with ID_LABEL_FS_ENC which is done with // udev encodes the labels with ID_LABEL_FS_ENC which is done with
// blkid_encode_string(). Within this function some 1-byte utf-8 // blkid_encode_string(). Within this function some 1-byte utf-8
// characters not considered safe (e.g. '\' or ' ') are encoded as hex // characters not considered safe (e.g. '\' or ' ') are encoded as hex
static QString decodeFsEncString(const QString &str) static QString decodeFsEncString(QString &&str)
{ {
QString decoded; using namespace QtMiscUtils;
decoded.reserve(str.size()); qsizetype start = str.indexOf(u'\\');
if (start < 0)
return std::move(str);
int i = 0; // decode in-place
while (i < str.size()) { QString decoded = std::move(str);
if (i <= str.size() - 4) { // we need at least four characters \xAB auto ptr = reinterpret_cast<char16_t *>(decoded.begin());
if (QStringView{str}.sliced(i).startsWith("\\x"_L1)) { qsizetype in = start;
bool bOk; qsizetype out = start;
const int code = QStringView{str}.mid(i+2, 2).toInt(&bOk, 16); qsizetype size = decoded.size();
if (bOk && code >= 0x20 && code < 0x80) {
decoded += QChar(code); while (in < size) {
i += 4; Q_ASSERT(ptr[in] == u'\\');
continue; if (size - in >= 4 && ptr[in + 1] == u'x') { // we need four characters: \xAB
} int c = fromHex(ptr[in + 2]) << 4;
} c |= fromHex(ptr[in + 3]);
if (Q_UNLIKELY(c < 0))
c = QChar::ReplacementCharacter; // bad hex sequence
ptr[out++] = c;
in += 4;
}
for ( ; in < size; ++in) {
char16_t c = ptr[in];
if (c == u'\\')
break;
ptr[out++] = c;
} }
decoded += str.at(i);
++i;
} }
decoded.resize(out);
return decoded; return decoded;
} }