6#include "private/qurl_p.h"
7#include "private/qstringconverter_p.h"
8#include "private/qtools_p.h"
9#include "private/qsimd_p.h"
101 0xff, 0xff, 0xff, 0xff, 0xff,
102 0xff, 0xff, 0xff, 0xff, 0xff,
111 0xff, 0xff, 0xff, 0xff, 0xff,
112 0xff, 0xff, 0xff, 0xff, 0xff,
113 0xff, 0xff, 0xff, 0xff, 0xff,
114 0xff, 0xff, 0xff, 0xff, 0xff,
115 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
123 0xff, 0xff, 0xff, 0xff, 0xff,
124 0xff, 0xff, 0xff, 0xff, 0xff,
125 0xff, 0xff, 0xff, 0xff, 0xff,
126 0xff, 0xff, 0xff, 0xff, 0xff,
127 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
138 return (c >= u'a' && c <= u'f') || (c >= u'A' && c <= u'F') || (c >= u'0' && c <= u'9');
154 return c >= u'a' ? c - u'a' + 0xA : c >= u'A' ? c - u'A' + 0xA : c - u'0';
162 char16_t c1 = input[1];
163 char16_t c2 = input[2];
166 return decodeNibble(c1) << 4 | decodeNibble(c2);
171 return QtMiscUtils::toHexUpper(c);
174static void ensureDetached(QString &result,
char16_t *&output,
const char16_t *begin,
const char16_t *input,
const char16_t *end,
180 int charsProcessed = input - begin;
181 int charsRemaining = end - input;
182 int spaceNeeded = end - begin + 2 * charsRemaining + add;
183 int origSize = result.size();
184 result.resize(origSize + spaceNeeded);
187 output =
const_cast<
char16_t *>(
reinterpret_cast<
const char16_t *>(result.constData()))
192 for (i = 0; i < charsProcessed; ++i)
193 output[i] = begin[i];
199struct QUrlUtf8Traits :
public QUtf8BaseTraitsNoAscii
223 static const bool allowNonCharacters =
false;
226 static void appendByte(
char16_t *&ptr, uchar b)
230 *ptr++ = encodeNibble(b >> 4);
231 *ptr++ = encodeNibble(b & 0xf);
234 static uchar peekByte(
const char16_t *ptr, qsizetype n = 0)
240 return uchar(decodePercentEncoding(ptr + n * 3))
241 * uchar(ptr[n * 3] ==
'%');
244 static qptrdiff availableBytes(
const char16_t *ptr,
const char16_t *end)
246 return (end - ptr) / 3;
249 static void advanceByte(
const char16_t *&ptr,
int n = 1)
258 const char16_t *&input,
const char16_t *end,
char16_t decoded)
261 char32_t &ucs4 = buffer[0];
262 char32_t *dst = buffer;
263 const char16_t *src = input + 3;
264 int charsNeeded = QUtf8Functions::fromUtf8<QUrlUtf8Traits>(decoded, dst, src, end);
268 if (!QChar::requiresSurrogates(ucs4)) {
272 ensureDetached(result, output, begin, input, end, -3 * charsNeeded + 1);
277 ensureDetached(result, output, begin, input, end, -10);
278 *output++ = QChar::highSurrogate(ucs4);
279 *output++ = QChar::lowSurrogate(ucs4);
287 const char16_t *&input,
const char16_t *end,
char16_t decoded)
290 int utf8len = QChar::isHighSurrogate(decoded) ? 4 : decoded >= 0x800 ? 3 : 2;
296 ensureDetached(result, output, begin, input, end, 3*utf8len - 3);
299 int charsRemaining = end - input - 1;
300 int pos = output -
reinterpret_cast<
const char16_t *>(result.constData());
301 int spaceRemaining = result.size() - pos;
302 if (spaceRemaining < 3*charsRemaining + 3*utf8len) {
304 result.resize(result.size() + 3*utf8len);
307 output =
const_cast<
char16_t *>(
reinterpret_cast<
const char16_t *>(result.constData()));
313 int res = QUtf8Functions::toUtf8<QUrlUtf8Traits>(decoded, output, input, end);
321 uchar c = 0xe0 | uchar(decoded >> 12);
324 *output++ = encodeNibble(c & 0xf);
327 c = 0x80 | (uchar(decoded >> 6) & 0x3f);
329 *output++ = encodeNibble(c >> 4);
330 *output++ = encodeNibble(c & 0xf);
333 c = 0x80 | (decoded & 0x3f);
335 *output++ = encodeNibble(c >> 4);
336 *output++ = encodeNibble(c & 0xf);
340static int recode(QString &result,
const char16_t *begin,
const char16_t *end,
341 QUrl::ComponentFormattingOptions encoding,
const uchar *actionTable,
342 bool retryBadEncoding)
344 const int origSize = result.size();
345 const char16_t *input = begin;
346 char16_t *output =
nullptr;
349 for ( ; input != end; ++input) {
352 for ( ; input != end; ++input) {
356 if (c < 0x20U || c >= 0x80U)
368 if (c ==
'%' && retryBadEncoding) {
370 ensureDetached(result, output, begin, input, end);
375 }
else if (c ==
'%') {
379 result.resize(origSize);
380 return recode(result, begin, end, encoding, actionTable,
true);
383 if (decoded >= 0x80) {
385 if (!(encoding & QUrl::EncodeUnicode) &&
386 encodedUtf8ToUtf16(result, output, begin, input, end, decoded))
391 }
else if (decoded >= 0x20) {
396 if (decoded >= 0x80 && encoding & QUrl::EncodeUnicode) {
398 unicodeToEncodedUtf8(result, output, begin, input, end, decoded);
400 }
else if (decoded >= 0x80) {
417 ensureDetached(result, output, begin, input, end);
424 ensureDetached(result, output, begin, input, end);
429 ensureDetached(result, output, begin, input, end);
431 *output++ = encodeNibble(c >> 4);
432 *output++ = encodeNibble(c & 0xf);
437 int len = output -
reinterpret_cast<
const char16_t *>(result.constData());
438 result.truncate(len);
439 return len - origSize;
445
446
447
448
450static bool simdCheckNonEncoded(QChar *&output,
const char16_t *&input,
const char16_t *end)
453 const __m256i percents256 = _mm256_broadcastw_epi16(_mm_cvtsi32_si128(
'%'));
454 const __m128i percents = _mm256_castsi256_si128(percents256);
456 const __m128i percents = _mm_set1_epi16(
'%');
461 if (input + 16 <= end) {
463 for ( ; input + offset + 16 <= end; offset += 16) {
466 __m256i data = _mm256_loadu_si256(
reinterpret_cast<
const __m256i *>(input + offset));
467 __m256i comparison = _mm256_cmpeq_epi16(data, percents256);
468 mask = _mm256_movemask_epi8(comparison);
469 _mm256_storeu_si256(
reinterpret_cast<__m256i *>(output + offset), data);
472 __m128i data1 = _mm_loadu_si128(
reinterpret_cast<
const __m128i *>(input + offset));
473 __m128i data2 = _mm_loadu_si128(
reinterpret_cast<
const __m128i *>(input + offset + 8));
474 __m128i comparison1 = _mm_cmpeq_epi16(data1, percents);
475 __m128i comparison2 = _mm_cmpeq_epi16(data2, percents);
476 uint mask1 = _mm_movemask_epi8(comparison1);
477 uint mask2 = _mm_movemask_epi8(comparison2);
479 _mm_storeu_si128(
reinterpret_cast<__m128i *>(output + offset), data1);
481 _mm_storeu_si128(
reinterpret_cast<__m128i *>(output + offset + 8), data2);
482 mask = mask1 | (mask2 << 16);
486 idx = qCountTrailingZeroBits(mask) / 2;
494 }
else if (input + 8 <= end) {
496 __m128i data = _mm_loadu_si128(
reinterpret_cast<
const __m128i *>(input));
497 __m128i comparison = _mm_cmpeq_epi16(data, percents);
498 mask = _mm_movemask_epi8(comparison);
499 _mm_storeu_si128(
reinterpret_cast<__m128i *>(output), data);
500 idx = qCountTrailingZeroBits(quint16(mask)) / 2;
501 }
else if (input + 4 <= end) {
503 __m128i data = _mm_loadl_epi64(
reinterpret_cast<
const __m128i *>(input));
504 __m128i comparison = _mm_cmpeq_epi16(data, percents);
505 mask = _mm_movemask_epi8(comparison) & 0xffu;
506 _mm_storel_epi64(
reinterpret_cast<__m128i *>(output), data);
507 idx = qCountTrailingZeroBits(quint8(mask)) / 2;
520static bool simdCheckNonEncoded(...)
532 if (byte == 0 || byte >= 0x80 || byte ==
'/')
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
574 QUrl::ComponentFormattingOptions encoding)
576 const bool forLocalFile = encoding.testFlags(QUrlDecodeForLocalFile);
577 const char16_t *begin = in.utf16();
578 const char16_t *end = begin + in.size();
582 if (forLocalFile && in.contains(u'\\')) {
583 if (appendTo.isEmpty())
584 appendTo = QString();
590 const char16_t *input = QtPrivate::qustrchr(in,
'%');
592 if (Q_LIKELY(input == end))
596 const int origSize = appendTo.size();
597 appendTo.resize(origSize + (end - begin));
598 QChar *output = appendTo.data() + origSize;
599 memcpy(
static_cast<
void *>(output),
static_cast<
const void *>(begin), (input - begin) *
sizeof(QChar));
600 output += input - begin;
602 while (input != end) {
604 Q_ASSERT(*input ==
'%');
606 if (Q_UNLIKELY(end - input < 3 || !
isHex(input[1]
) || !
isHex(input[2]
))) {
608 appendTo.resize(origSize + (end - begin));
609 memcpy(
static_cast<
void *>(appendTo.begin() + origSize),
610 static_cast<
const void *>(begin), (end - begin) *
sizeof(*end));
615 uchar byte = decodeNibble(input[0]) << 4 | decodeNibble(input[1]);
616 *output++ = QChar::fromUcs2(byte);
617 if (forLocalFile && Q_UNLIKELY(isUnsafeForLocalFile(byte))) {
619 appendTo = QString();
621 appendTo.truncate(origSize);
625 output[-1] = QChar::ReplacementCharacter;
629 if (simdCheckNonEncoded(output, input, end)) {
630 while (input != end) {
631 const char16_t uc = *input;
640 const qsizetype len = output - appendTo.begin();
641 appendTo.truncate(len);
642 return len - origSize;
646static void maskTable(uchar (&table)[N],
const uchar (&mask)[N])
648 for (size_t i = 0; i < N; ++i)
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
696Q_AUTOTEST_EXPORT qsizetype
697qt_urlRecode(QString &appendTo, QStringView in,
698 QUrl::ComponentFormattingOptions encoding,
const ushort *tableModifications)
700 uchar actionTable[
sizeof defaultActionTable];
701 if ((encoding & QUrl::FullyDecoded) == QUrl::FullyDecoded) {
702 return decode(appendTo, in, encoding);
705 memcpy(actionTable, defaultActionTable,
sizeof actionTable);
706 if (encoding & QUrl::DecodeReserved)
707 maskTable(actionTable, reservedMask);
708 if (encoding & QUrl::EncodeSpaces)
709 actionTable[0] = EncodeCharacter;
711 if (tableModifications) {
712 for (
const ushort *p = tableModifications; *p; ++p)
713 actionTable[uchar(*p) -
' '] = *p >> 8;
716 return recode(appendTo,
reinterpret_cast<
const char16_t *>(in.begin()),
717 reinterpret_cast<
const char16_t *>(in.end()), encoding, actionTable,
false);
723 memcpy(actionTable, defaultActionTable,
sizeof actionTable);
729 if (tableModifications) {
730 for (
const ushort *p = tableModifications; *p; ++p)
731 actionTable[uchar(*p) -
' '] = *p >> 8;
734 return recode(appendTo,
reinterpret_cast<
const char16_t *>(in.begin()),
735 reinterpret_cast<
const char16_t *>(in.end()), {}, actionTable,
true);
Combined button and popup list for selecting options.
qsizetype qt_encodeFromUser(QString &appendTo, const QString &input, const ushort *tableModifications)
static char16_t decodePercentEncoding(const char16_t *input)
static bool encodedUtf8ToUtf16(QString &result, char16_t *&output, const char16_t *begin, const char16_t *&input, const char16_t *end, char16_t decoded)
static qsizetype decode(QString &appendTo, QStringView in, QUrl::ComponentFormattingOptions encoding)
static int recode(QString &result, const char16_t *begin, const char16_t *end, QUrl::ComponentFormattingOptions encoding, const uchar *actionTable, bool retryBadEncoding)
static ushort decodeNibble(char16_t c)
static bool isUnsafeForLocalFile(uchar byte)
static char16_t encodeNibble(ushort c)
static const uchar reservedMask[96]
static char16_t toUpperHex(char16_t c)
static bool isUpperHex(char16_t c)
static void maskTable(uchar(&table)[N], const uchar(&mask)[N])
static void unicodeToEncodedUtf8(QString &result, char16_t *&output, const char16_t *begin, const char16_t *&input, const char16_t *end, char16_t decoded)
static const uchar defaultActionTable[96]
static void ensureDetached(QString &result, char16_t *&output, const char16_t *begin, const char16_t *input, const char16_t *end, int add=0)
static bool isHex(char16_t c)