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

source code of qtbase/src/corelib/io/qurlquery.cpp