Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qurlquery.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 Intel Corporation.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
5#include "qurlquery.h"
6#include "qurl_p.h"
7
8#include <QtCore/qhashfunctions.h>
9#include <QtCore/qstringlist.h>
10
11#include <algorithm>
12
13QT_BEGIN_NAMESPACE
14
15/*!
16 \class QUrlQuery
17 \inmodule QtCore
18 \since 5.0
19
20 \brief The QUrlQuery class provides a way to manipulate a key-value pairs in
21 a URL's query.
22
23 \reentrant
24 \ingroup io
25 \ingroup network
26 \ingroup shared
27
28 \compares equality
29
30 It is used to parse the query strings found in URLs like the following:
31
32 \image qurl-querystring.png {Illustration of a URL with part after question mark
33 highlighted as query string.}
34
35 Query strings like the above are used to transmit options in the URL and are
36 usually decoded into multiple key-value pairs. The one above would contain
37 two entries in its list, with keys "type" and "color". QUrlQuery can also be
38 used to create a query string suitable for use in QUrl::setQuery() from the
39 individual components of the query.
40
41 The most common way of parsing a query string is to initialize it in the
42 constructor by passing it the query string. Otherwise, the setQuery() method
43 can be used to set the query to be parsed. That method can also be used to
44 parse a query with non-standard delimiters, after having set them using the
45 setQueryDelimiters() function.
46
47 The encoded query string can be obtained again using query(). This will take
48 all the internally-stored items and encode the string using the delimiters.
49
50 \section1 Encoding
51
52 All of the getter methods in QUrlQuery support an optional parameter of type
53 QUrl::ComponentFormattingOptions, including query(), which dictate how to
54 encode the data in question. Except for QUrl::FullyDecoded, the returned value must
55 still be considered a percent-encoded string, as there are certain values
56 which cannot be expressed in decoded form (like control characters, byte
57 sequences not decodable to UTF-8). For that reason, the percent character is
58 always represented by the string "%25".
59
60 All of the setter methods and the query methods like hasQueryItem() in
61 QUrlQuery take encoded forms only. Unlike in QUrl, there's no optional
62 parameter to specify that the strings being passed are decoded. If
63 improperly-encoded strings are passed to the setter or query methods,
64 QUrlQuery will attempt to recover instead of failing. That is to say, all
65 functions in this class parse their string arguments as if the
66 QUrl::TolerantMode decoding mode was specified.
67
68 Application code should strive to always ensure proper encoding and not rely
69 on TolerantMode parsing fixing the strings. Notably, all user input must be
70 first percent-encoded using QUrl::toPercentEncoding() or similar functions
71 before being passed to the functions in this class.
72
73 \section2 Handling of spaces and plus ("+")
74
75 Web browsers usually encode spaces found in HTML FORM elements to a plus sign
76 ("+") and plus signs to its percent-encoded form (%2B). However, the Internet
77 specifications governing URLs do not consider spaces and the plus character
78 equivalent.
79
80 For that reason, QUrlQuery never encodes the space character to "+" and will
81 never decode "+" to a space character. Instead, space characters will be
82 rendered "%20" in encoded form.
83
84 To support encoding like that of HTML forms, QUrlQuery also never decodes the
85 "%2B" sequence to a plus sign nor encode a plus sign. In fact, any "%2B" or
86 "+" sequences found in the keys, values, or query string are left exactly
87 like written (except for the uppercasing of "%2b" to "%2B").
88
89 \section2 Full decoding
90
91 With QUrl::FullyDecoded formatting, all percent-encoded sequences will be
92 decoded fully and the '%' character is used to represent itself.
93 QUrl::FullyDecoded should be used with care, since it may cause data loss.
94 See the documentation of QUrl::FullyDecoded for information on what data may
95 be lost.
96
97 This formatting mode should be used only when dealing with text presented to
98 the user in contexts where percent-encoding is not desired. Note that
99 QUrlQuery setters and query methods do not support the counterpart
100 QUrl::DecodedMode parsing, so using QUrl::FullyDecoded to obtain a listing of
101 keys may result in keys not found in the object.
102
103 \section1 Non-standard delimiters
104
105 By default, QUrlQuery uses an equal sign ("=") to separate a key from its
106 value, and an ampersand ("&") to separate key-value pairs from each other. It
107 is possible to change the delimiters that QUrlQuery uses for parsing and for
108 reconstructing the query by calling setQueryDelimiters().
109
110 Non-standard delimiters should be chosen from among what RFC 3986 calls
111 "sub-delimiters". They are:
112
113 \snippet code/src_corelib_io_qurlquery.cpp 0
114
115 Use of other characters is not supported and may result in unexpected
116 behaviour. QUrlQuery does not verify that you passed a valid delimiter.
117
118 \sa QUrl
119*/
120
121/*!
122 \fn QUrlQuery &QUrlQuery::operator=(QUrlQuery &&other)
123
124 Move-assigns \a other to this QUrlQuery instance.
125
126 \since 5.2
127*/
128
129/*!
130 \fn QUrlQuery::QUrlQuery(std::initializer_list<std::pair<QString, QString>> list)
131
132 \since 5.13
133
134 Constructs a QUrlQuery object from the \a list of key/value pair.
135*/
136
137typedef QList<std::pair<QString, QString> > Map;
138
140{
141public:
142 QUrlQueryPrivate(const QString &query = QString())
145 { if (!query.isEmpty()) setQuery(query); }
146
147 QString recodeFromUser(const QString &input) const;
148 QString recodeToUser(const QString &input, QUrl::ComponentFormattingOptions encoding) const;
149
150 void setQuery(const QString &query);
151
152 void addQueryItem(const QString &key, const QString &value)
153 { itemList.append(std::make_pair(recodeFromUser(key), recodeFromUser(value))); }
154 int findRecodedKey(const QString &key, int from = 0) const
155 {
156 for (int i = from; i < itemList.size(); ++i)
157 if (itemList.at(i).first == key)
158 return i;
159 return itemList.size();
160 }
161 Map::const_iterator findKey(const QString &key) const
162 { return itemList.constBegin() + findRecodedKey(recodeFromUser(key)); }
163 Map::iterator findKey(const QString &key)
164 { return itemList.begin() + findRecodedKey(recodeFromUser(key)); }
165
169};
170
171template<> void QSharedDataPointer<QUrlQueryPrivate>::detach()
172{
173 if (d && d->ref.loadRelaxed() == 1)
174 return;
175 QUrlQueryPrivate *x = (d ? new QUrlQueryPrivate(*d)
176 : new QUrlQueryPrivate);
177 x->ref.ref();
178 if (d && !d->ref.deref())
179 delete d.get();
180 d.reset(x);
181}
182
183// Here's how we do the encoding in QUrlQuery
184// The RFC says these are the delimiters:
185// gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
186// sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
187// / "*" / "+" / "," / ";" / "="
188// And the definition of query is:
189// query = *( pchar / "/" / "?" )
190// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
191//
192// The strict definition of query says that it can have unencoded any
193// unreserved, sub-delim, ":", "@", "/" and "?". Or, by exclusion, excluded
194// delimiters are "#", "[" and "]" -- if those are present, they must be
195// percent-encoded. The fact that "[" and "]" should be encoded is probably a
196// mistake in the spec, so we ignore it and leave the decoded.
197//
198// The internal storage in the Map is equivalent to PrettyDecoded. That means
199// the getter methods, when called with the default encoding value, will not
200// have to recode anything (except for toString()).
201//
202// QUrlQuery handling of delimiters is quite simple: we never touch any of
203// them, except for the "#" character and the pair and value delimiters. Those
204// are always kept in their decoded forms.
205//
206// But when recreating the query string, in toString(), we must take care of
207// the special delimiters: the pair and value delimiters, as well as the "#"
208// character if unambiguous decoding is requested.
209
210#define decode(x) ushort(x)
211#define leave(x) ushort(0x100 | (x))
212#define encode(x) ushort(0x200 | (x))
213
214inline QString QUrlQueryPrivate::recodeFromUser(const QString &input) const
215{
216 // note: duplicated in setQuery()
217 QString output;
218 ushort prettyDecodedActions[] = {
219 decode(pairDelimiter.unicode()),
220 decode(valueDelimiter.unicode()),
221 decode('#'),
222 0
223 };
224 if (qt_urlRecode(output, input,
225 QUrl::DecodeReserved,
226 prettyDecodedActions))
227 return output;
228 return input;
229}
230
231inline bool idempotentRecodeToUser(QUrl::ComponentFormattingOptions encoding)
232{
233 return encoding == QUrl::PrettyDecoded;
234}
235
236inline QString QUrlQueryPrivate::recodeToUser(const QString &input, QUrl::ComponentFormattingOptions encoding) const
237{
238 // our internal formats are stored in "PrettyDecoded" form
239 // and there are no ambiguous characters
240 if (idempotentRecodeToUser(encoding))
241 return input;
242
243 if (!(encoding & QUrl::EncodeDelimiters)) {
244 QString output;
245 if (qt_urlRecode(output, input,
246 encoding, nullptr))
247 return output;
248 return input;
249 }
250
251 // re-encode the "#" character and the query delimiter pair
252 ushort actions[] = { encode(pairDelimiter.unicode()), encode(valueDelimiter.unicode()),
253 encode('#'), 0 };
254 QString output;
255 if (qt_urlRecode(output, input, encoding, actions))
256 return output;
257 return input;
258}
259
260void QUrlQueryPrivate::setQuery(const QString &query)
261{
262 ushort prettyDecodedActions[] = {
263 decode(pairDelimiter.unicode()),
264 decode(valueDelimiter.unicode()),
265 decode('#'),
266 0
267 };
268
269 itemList.clear();
270 const QChar *pos = query.constData();
271 const QChar *const end = pos + query.size();
272 while (pos != end) {
273 const QChar *begin = pos;
274 const QChar *delimiter = nullptr;
275 while (pos != end) {
276 // scan for the component parts of this pair
277 if (!delimiter && *pos == valueDelimiter)
278 delimiter = pos;
279 if (*pos == pairDelimiter)
280 break;
281 ++pos;
282 }
283 if (!delimiter)
284 delimiter = pos;
285
286 // pos is the end of this pair (the end of the string or the pair delimiter)
287 // delimiter points to the value delimiter or to the end of this pair
288
289 QString key;
290 if (!qt_urlRecode(key, QStringView{begin, delimiter},
291 QUrl::DecodeReserved,
292 prettyDecodedActions))
293 key = QString(begin, delimiter - begin);
294
295 if (delimiter == pos) {
296 // the value delimiter wasn't found, store a null value
297 itemList.append(std::make_pair(key, QString()));
298 } else if (delimiter + 1 == pos) {
299 // if the delimiter was found but the value is empty, store empty-but-not-null
300 itemList.append(std::make_pair(key, QString(0, Qt::Uninitialized)));
301 } else {
302 QString value;
303 if (!qt_urlRecode(value, QStringView{delimiter + 1, pos},
304 QUrl::DecodeReserved,
305 prettyDecodedActions))
306 value = QString(delimiter + 1, pos - delimiter - 1);
307 itemList.append(std::make_pair(key, value));
308 }
309
310 if (pos != end)
311 ++pos;
312 }
313}
314
315// allow QUrlQueryPrivate to detach from null
316template <> inline QUrlQueryPrivate *
317QSharedDataPointer<QUrlQueryPrivate>::clone()
318{
319 return d ? new QUrlQueryPrivate(*d) : new QUrlQueryPrivate;
320}
321
322/*!
323 Constructs an empty QUrlQuery object. A query can be set afterwards by
324 calling setQuery() or items can be added by using addQueryItem().
325
326 \sa setQuery(), addQueryItem()
327*/
328QUrlQuery::QUrlQuery()
329 : d(nullptr)
330{
331}
332
333/*!
334 Constructs a QUrlQuery object and parses the \a queryString query string,
335 using the default query delimiters. To parse a query string using other
336 delimiters, you should first set them using setQueryDelimiters() and then
337 set the query with setQuery().
338*/
339QUrlQuery::QUrlQuery(const QString &queryString)
340 : d(queryString.isEmpty() ? nullptr : new QUrlQueryPrivate(queryString))
341{
342}
343
344/*!
345 Constructs a QUrlQuery object and parses the query string found in the \a
346 url URL, using the default query delimiters. To parse a query string using
347 other delimiters, you should first set them using setQueryDelimiters() and
348 then set the query with setQuery().
349
350 \sa QUrl::query()
351*/
352QUrlQuery::QUrlQuery(const QUrl &url)
353 : d(nullptr)
354{
355 // use internals to avoid unnecessary recoding
356 // ### FIXME: actually do it
357 if (url.hasQuery())
358 d = new QUrlQueryPrivate(url.query());
359}
360
361/*!
362 Copies the contents of the \a other QUrlQuery object, including the query
363 delimiters.
364*/
365QUrlQuery::QUrlQuery(const QUrlQuery &other)
366 : d(other.d)
367{
368}
369
370/*!
371 \since 6.5
372 Moves the contents of the \a other QUrlQuery object, including the query
373 delimiters.
374*/
375QUrlQuery::QUrlQuery(QUrlQuery &&other) noexcept
376 : d(std::move(other.d))
377{
378}
379
380/*!
381 Copies the contents of the \a other QUrlQuery object, including the query
382 delimiters.
383*/
384QUrlQuery &QUrlQuery::operator =(const QUrlQuery &other)
385{
386 d = other.d;
387 return *this;
388}
389
390/*!
391 \fn void QUrlQuery::swap(QUrlQuery &other)
392 \memberswap{URL query instance}
393*/
394
395/*!
396 Destroys this QUrlQuery object.
397*/
398QUrlQuery::~QUrlQuery()
399{
400 // d auto-deletes
401}
402
403/*!
404 \fn bool QUrlQuery::operator==(const QUrlQuery &lhs, const QUrlQuery &rhs)
405
406 Returns \c true if QUrlQuery objects \a lhs and \a rhs contain the same
407 contents, in the same order, and use the same query delimiters.
408*/
409
410bool comparesEqual(const QUrlQuery &lhs, const QUrlQuery &rhs)
411{
412 if (lhs.d == rhs.d)
413 return true;
414 if (lhs.d && rhs.d)
415 // keep in sync with qHash(QUrlQuery):
416 return lhs.d->valueDelimiter == rhs.d->valueDelimiter &&
417 lhs.d->pairDelimiter == rhs.d->pairDelimiter &&
418 lhs.d->itemList == rhs.d->itemList;
419
420 const QUrlQueryPrivate *x = lhs.d ? lhs.d.data() : rhs.d.data();
421 return x->valueDelimiter == QUrlQuery::defaultQueryValueDelimiter() &&
422 x->pairDelimiter == QUrlQuery::defaultQueryPairDelimiter() &&
423 x->itemList.isEmpty();
424}
425
426/*!
427 \since 5.6
428 \qhashold{QUrlQuery}
429*/
430size_t qHash(const QUrlQuery &key, size_t seed) noexcept
431{
432 if (const QUrlQueryPrivate *d = key.d) {
433 // keep in sync with operator==:
434 return qHashMulti(seed, d->valueDelimiter, d->pairDelimiter, d->itemList);
435 }
436 return seed;
437}
438
439/*!
440 Returns \c true if this QUrlQuery object contains no key-value pairs, such as
441 after being default-constructed or after parsing an empty query string.
442
443 \sa setQuery(), clear()
444*/
445bool QUrlQuery::isEmpty() const
446{
447 return d ? d->itemList.isEmpty() : true;
448}
449
450/*!
451 \internal
452*/
453bool QUrlQuery::isDetached() const
454{
455 return d && d->ref.loadRelaxed() == 1;
456}
457
458/*!
459 Clears this QUrlQuery object by removing all of the key-value pairs
460 currently stored. If the query delimiters have been changed, this function
461 will leave them with their changed values.
462
463 \sa isEmpty(), setQueryDelimiters()
464*/
465void QUrlQuery::clear()
466{
467 if (d.constData())
468 d->itemList.clear();
469}
470
471/*!
472 Parses the query string in \a queryString and sets the internal items to
473 the values found there. If any delimiters have been specified with
474 setQueryDelimiters(), this function will use them instead of the default
475 delimiters to parse the string.
476*/
477void QUrlQuery::setQuery(const QString &queryString)
478{
479 d->setQuery(queryString);
480}
481
482static void recodeAndAppend(QString &to, const QString &input,
483 QUrl::ComponentFormattingOptions encoding, const ushort *tableModifications)
484{
485 if (!qt_urlRecode(to, input, encoding, tableModifications))
486 to += input;
487}
488
489/*!
490 Returns the reconstructed query string, formed from the key-value pairs
491 currently stored in this QUrlQuery object and separated by the query
492 delimiters chosen for this object. The keys and values are encoded using
493 the options given by the \a encoding parameter.
494
495 For this function, the only ambiguous delimiter is the hash ("#"), as in
496 URLs it is used to separate the query string from the fragment that may
497 follow.
498
499 The order of the key-value pairs in the returned string is exactly the same
500 as in the original query.
501
502 \sa setQuery(), QUrl::setQuery(), QUrl::fragment(), {encoding}{Encoding}
503*/
504QString QUrlQuery::query(QUrl::ComponentFormattingOptions encoding) const
505{
506 if (!d)
507 return QString();
508
509 // unlike the component encoding, for the whole query we need to modify a little:
510 // - the "#" character is unambiguous, so we encode it in EncodeDelimiters mode
511 // - the query delimiter pair must always be encoded
512
513 // start with what's always encoded
514 ushort tableActions[] = {
515 encode(d->pairDelimiter.unicode()), // 0
516 encode(d->valueDelimiter.unicode()), // 1
517 0, // 2
518 0
519 };
520 if (encoding & QUrl::EncodeDelimiters) {
521 tableActions[2] = encode('#');
522 }
523
524 QString result;
525 Map::const_iterator it = d->itemList.constBegin();
526 Map::const_iterator end = d->itemList.constEnd();
527
528 {
529 int size = 0;
530 for ( ; it != end; ++it)
531 size += it->first.size() + 1 + it->second.size() + 1;
532 result.reserve(size + size / 4);
533 }
534
535 for (it = d->itemList.constBegin(); it != end; ++it) {
536 if (!result.isEmpty())
537 result += QChar(d->pairDelimiter);
538 recodeAndAppend(result, it->first, encoding, tableActions);
539 if (!it->second.isNull()) {
540 result += QChar(d->valueDelimiter);
541 recodeAndAppend(result, it->second, encoding, tableActions);
542 }
543 }
544 return result;
545}
546
547/*!
548 Sets the characters used for delimiting between keys and values,
549 and between key-value pairs in the URL's query string. The default
550 value delimiter is '=' and the default pair delimiter is '&'.
551
552 \image qurl-querystring.png {Illustration of a URL with part after
553 question mark highlighted as query string.}
554
555 \a valueDelimiter will be used for separating keys from values,
556 and \a pairDelimiter will be used to separate key-value pairs.
557 Any occurrences of these delimiting characters in the encoded
558 representation of the keys and values of the query string are
559 percent encoded when returned in query().
560
561 If \a valueDelimiter is set to ',' and \a pairDelimiter is ';',
562 the above query string would instead be represented like this:
563
564 \snippet code/src_corelib_io_qurl.cpp 4
565
566 \note Non-standard delimiters should be chosen from among what RFC 3986 calls
567 "sub-delimiters". They are:
568
569 \snippet code/src_corelib_io_qurlquery.cpp 0
570
571 Use of other characters is not supported and may result in unexpected
572 behavior. This method does not verify that you passed a valid delimiter.
573
574 \sa queryValueDelimiter(), queryPairDelimiter()
575*/
576void QUrlQuery::setQueryDelimiters(QChar valueDelimiter, QChar pairDelimiter)
577{
578 d->valueDelimiter = valueDelimiter;
579 d->pairDelimiter = pairDelimiter;
580}
581
582/*!
583 Returns the character used to delimit between keys and values when
584 reconstructing the query string in query() or when parsing in setQuery().
585
586 \sa setQueryDelimiters(), queryPairDelimiter()
587*/
588QChar QUrlQuery::queryValueDelimiter() const
589{
590 return d ? d->valueDelimiter : defaultQueryValueDelimiter();
591}
592
593/*!
594 Returns the character used to delimit between keys-value pairs when
595 reconstructing the query string in query() or when parsing in setQuery().
596
597 \sa setQueryDelimiters(), queryValueDelimiter()
598*/
599QChar QUrlQuery::queryPairDelimiter() const
600{
601 return d ? d->pairDelimiter : defaultQueryPairDelimiter();
602}
603
604/*!
605 Sets the items in this QUrlQuery object to \a query. The order of the
606 elements in \a query is preserved.
607
608 \note This method does not treat spaces (ASCII 0x20) and plus ("+") signs
609 as the same, like HTML forms do. If you need spaces to be represented as
610 plus signs, use actual plus signs.
611
612 \note The keys and values are expected to be in percent-encoded form.
613
614 \sa queryItems(), isEmpty()
615*/
616void QUrlQuery::setQueryItems(const QList<std::pair<QString, QString> > &query)
617{
618 clear();
619 if (query.isEmpty())
620 return;
621
622 QUrlQueryPrivate *dd = d;
623 QList<std::pair<QString, QString> >::const_iterator it = query.constBegin(),
624 end = query.constEnd();
625 for ( ; it != end; ++it)
626 dd->addQueryItem(it->first, it->second);
627}
628
629/*!
630 Returns the query string of the URL, as a map of keys and values, using the
631 options specified in \a encoding to encode the items. The order of the
632 elements is the same as the one found in the query string or set with
633 setQueryItems().
634
635 \sa setQueryItems(), {encoding}{Encoding}
636*/
637QList<std::pair<QString, QString> > QUrlQuery::queryItems(QUrl::ComponentFormattingOptions encoding) const
638{
639 if (!d)
640 return QList<std::pair<QString, QString> >();
641 if (idempotentRecodeToUser(encoding))
642 return d->itemList;
643
644 QList<std::pair<QString, QString> > result;
645 Map::const_iterator it = d->itemList.constBegin();
646 Map::const_iterator end = d->itemList.constEnd();
647 result.reserve(d->itemList.size());
648 for ( ; it != end; ++it)
649 result << std::make_pair(d->recodeToUser(it->first, encoding),
650 d->recodeToUser(it->second, encoding));
651 return result;
652}
653
654/*!
655 Returns \c true if there is a query string pair whose key is equal
656 to \a key from the URL.
657
658 \note The key expected to be in percent-encoded form.
659
660 \sa addQueryItem(), queryItemValue()
661*/
662bool QUrlQuery::hasQueryItem(const QString &key) const
663{
664 if (!d)
665 return false;
666 return d->findKey(key) != d->itemList.constEnd();
667}
668
669/*!
670 Appends the pair \a key = \a value to the end of the query string of the
671 URL. This method does not overwrite existing items that might exist with
672 the same key.
673
674 \note This method does not treat spaces (ASCII 0x20) and plus ("+") signs
675 as the same, like HTML forms do. If you need spaces to be represented as
676 plus signs, use actual plus signs.
677
678 \note The key and value strings are expected to be in percent-encoded form.
679
680 \sa hasQueryItem(), queryItemValue()
681*/
682void QUrlQuery::addQueryItem(const QString &key, const QString &value)
683{
684 d->addQueryItem(key, value);
685}
686
687/*!
688 Returns the query value associated with key \a key from the URL, using the
689 options specified in \a encoding to encode the return value. If the key \a
690 key is not found, this function returns an empty string. If you need to
691 distinguish between an empty value and a non-existent key, you should check
692 for the key's presence first using hasQueryItem().
693
694 If the key \a key is multiply defined, this function will return the first
695 one found, in the order they were present in the query string or added
696 using addQueryItem().
697
698 \note The key is expected to be in percent-encoded form.
699
700 \sa addQueryItem(), allQueryItemValues(), {encoding}{Encoding}
701*/
702QString QUrlQuery::queryItemValue(const QString &key, QUrl::ComponentFormattingOptions encoding) const
703{
704 QString result;
705 if (d) {
706 Map::const_iterator it = d->findKey(key);
707 if (it != d->itemList.constEnd())
708 result = d->recodeToUser(it->second, encoding);
709 }
710 return result;
711}
712
713/*!
714 Returns the a list of query string values whose key is equal to \a key from
715 the URL, using the options specified in \a encoding to encode the return
716 value. If the key \a key is not found, this function returns an empty list.
717
718 \note The key is expected to be in percent-encoded form.
719
720 \sa queryItemValue(), addQueryItem()
721*/
722QStringList QUrlQuery::allQueryItemValues(const QString &key, QUrl::ComponentFormattingOptions encoding) const
723{
724 QStringList result;
725 if (d) {
726 QString encodedKey = d->recodeFromUser(key);
727 int idx = d->findRecodedKey(encodedKey);
728 while (idx < d->itemList.size()) {
729 result << d->recodeToUser(d->itemList.at(idx).second, encoding);
730 idx = d->findRecodedKey(encodedKey, idx + 1);
731 }
732 }
733 return result;
734}
735
736/*!
737 Removes the query string pair whose key is equal to \a key from the URL. If
738 there are multiple items with a key equal to \a key, it removes the first
739 item in the order they were present in the query string or added with
740 addQueryItem().
741
742 \note The key is expected to be in percent-encoded form.
743
744 \sa removeAllQueryItems()
745*/
746void QUrlQuery::removeQueryItem(const QString &key)
747{
748 if (d.constData()) {
749 auto *p = d.data();
750 Map::iterator it = p->findKey(key);
751 if (it != p->itemList.end())
752 p->itemList.erase(it);
753 }
754}
755
756/*!
757 Removes all the query string pairs whose key is equal to \a key
758 from the URL.
759
760 \note The key is expected to be in percent-encoded form.
761
762 \sa removeQueryItem()
763*/
764void QUrlQuery::removeAllQueryItems(const QString &key)
765{
766 if (d.constData()) {
767 auto *p = d.data();
768 const QString encodedKey = p->recodeFromUser(key);
769 auto firstEqualsEncodedKey = [&encodedKey](const std::pair<QString, QString> &item) {
770 return item.first == encodedKey;
771 };
772 p->itemList.removeIf(firstEqualsEncodedKey);
773 }
774}
775
776/*!
777 \fn QUrlQuery::defaultQueryValueDelimiter()
778 Returns the default character for separating keys from values in the query,
779 an equal sign ("=").
780
781 \note Prior to Qt 6, this function returned QChar.
782
783 \sa setQueryDelimiters(), queryValueDelimiter(), defaultQueryPairDelimiter()
784*/
785
786/*!
787 \fn QUrlQuery::defaultQueryPairDelimiter()
788 Returns the default character for separating keys-value pairs from each
789 other, an ampersand ("&").
790
791 \note Prior to Qt 6, this function returned QChar.
792
793 \sa setQueryDelimiters(), queryPairDelimiter(), defaultQueryValueDelimiter()
794*/
795
796/*!
797 \typedef QUrlQuery::DataPtr
798 \internal
799*/
800
801/*!
802 \fn DataPtr &QUrlQuery::data_ptr()
803 \internal
804*/
805
806/*!
807 \fn QString QUrlQuery::toString(QUrl::ComponentFormattingOptions encoding = QUrl::PrettyDecoded) const
808
809 Returns this QUrlQuery as a QString. \a encoding can be used to specify the URL string encoding of the return value.
810*/
811
812/*!
813 \fn bool QUrlQuery::operator!=(const QUrlQuery &lhs, const QUrlQuery &rhs)
814
815 Returns \c true if the QUrlQuery object \a rhs is not equal to \a lhs.
816 Otherwise, returns \c false.
817
818 \sa operator==()
819*/
820QT_END_NAMESPACE
821
822#undef decode
823#undef leave
824#undef encode
QUrlQueryPrivate(const QString &query=QString())
int findRecodedKey(const QString &key, int from=0) const
void addQueryItem(const QString &key, const QString &value)
void setQuery(const QString &query)
QString recodeFromUser(const QString &input) const
QString recodeToUser(const QString &input, QUrl::ComponentFormattingOptions encoding) const
Map::const_iterator findKey(const QString &key) const
Map::iterator findKey(const QString &key)
bool comparesEqual(const QFileInfo &lhs, const QFileInfo &rhs)
constexpr size_t qHash(const QSize &s, size_t seed=0) noexcept
Definition qsize.h:191
#define decode(x)
static void recodeAndAppend(QString &to, const QString &input, QUrl::ComponentFormattingOptions encoding, const ushort *tableModifications)
#define encode(x)
bool idempotentRecodeToUser(QUrl::ComponentFormattingOptions encoding)