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};
170QT_DEFINE_QSDP_SPECIALIZATION_DTOR(QUrlQueryPrivate)
171
172template<> void QSharedDataPointer<QUrlQueryPrivate>::detach()
173{
174 if (d && d->ref.loadRelaxed() == 1)
175 return;
176 QUrlQueryPrivate *x = (d ? new QUrlQueryPrivate(*d)
177 : new QUrlQueryPrivate);
178 x->ref.ref();
179 if (d && !d->ref.deref())
180 delete d.get();
181 d.reset(x);
182}
183
184// Here's how we do the encoding in QUrlQuery
185// The RFC says these are the delimiters:
186// gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
187// sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
188// / "*" / "+" / "," / ";" / "="
189// And the definition of query is:
190// query = *( pchar / "/" / "?" )
191// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
192//
193// The strict definition of query says that it can have unencoded any
194// unreserved, sub-delim, ":", "@", "/" and "?". Or, by exclusion, excluded
195// delimiters are "#", "[" and "]" -- if those are present, they must be
196// percent-encoded. The fact that "[" and "]" should be encoded is probably a
197// mistake in the spec, so we ignore it and leave the decoded.
198//
199// The internal storage in the Map is equivalent to PrettyDecoded. That means
200// the getter methods, when called with the default encoding value, will not
201// have to recode anything (except for toString()).
202//
203// QUrlQuery handling of delimiters is quite simple: we never touch any of
204// them, except for the "#" character and the pair and value delimiters. Those
205// are always kept in their decoded forms.
206//
207// But when recreating the query string, in toString(), we must take care of
208// the special delimiters: the pair and value delimiters, as well as the "#"
209// character if unambiguous decoding is requested.
210
211#define decode(x) ushort(x)
212#define leave(x) ushort(0x100 | (x))
213#define encode(x) ushort(0x200 | (x))
214
215inline QString QUrlQueryPrivate::recodeFromUser(const QString &input) const
216{
217 // note: duplicated in setQuery()
218 QString output;
219 ushort prettyDecodedActions[] = {
220 decode(pairDelimiter.unicode()),
221 decode(valueDelimiter.unicode()),
222 decode('#'),
223 0
224 };
225 if (qt_urlRecode(output, input,
226 QUrl::DecodeReserved,
227 prettyDecodedActions))
228 return output;
229 return input;
230}
231
232inline bool idempotentRecodeToUser(QUrl::ComponentFormattingOptions encoding)
233{
234 return encoding == QUrl::PrettyDecoded;
235}
236
237inline QString QUrlQueryPrivate::recodeToUser(const QString &input, QUrl::ComponentFormattingOptions encoding) const
238{
239 // our internal formats are stored in "PrettyDecoded" form
240 // and there are no ambiguous characters
241 if (idempotentRecodeToUser(encoding))
242 return input;
243
244 if (!(encoding & QUrl::EncodeDelimiters)) {
245 QString output;
246 if (qt_urlRecode(output, input,
247 encoding, nullptr))
248 return output;
249 return input;
250 }
251
252 // re-encode the "#" character and the query delimiter pair
253 ushort actions[] = { encode(pairDelimiter.unicode()), encode(valueDelimiter.unicode()),
254 encode('#'), 0 };
255 QString output;
256 if (qt_urlRecode(output, input, encoding, actions))
257 return output;
258 return input;
259}
260
261void QUrlQueryPrivate::setQuery(const QString &query)
262{
263 ushort prettyDecodedActions[] = {
264 decode(pairDelimiter.unicode()),
265 decode(valueDelimiter.unicode()),
266 decode('#'),
267 0
268 };
269
270 itemList.clear();
271 const QChar *pos = query.constData();
272 const QChar *const end = pos + query.size();
273 while (pos != end) {
274 const QChar *begin = pos;
275 const QChar *delimiter = nullptr;
276 while (pos != end) {
277 // scan for the component parts of this pair
278 if (!delimiter && *pos == valueDelimiter)
279 delimiter = pos;
280 if (*pos == pairDelimiter)
281 break;
282 ++pos;
283 }
284 if (!delimiter)
285 delimiter = pos;
286
287 // pos is the end of this pair (the end of the string or the pair delimiter)
288 // delimiter points to the value delimiter or to the end of this pair
289
290 QString key;
291 if (!qt_urlRecode(key, QStringView{begin, delimiter},
292 QUrl::DecodeReserved,
293 prettyDecodedActions))
294 key = QString(begin, delimiter - begin);
295
296 if (delimiter == pos) {
297 // the value delimiter wasn't found, store a null value
298 itemList.append(std::make_pair(key, QString()));
299 } else if (delimiter + 1 == pos) {
300 // if the delimiter was found but the value is empty, store empty-but-not-null
301 itemList.append(std::make_pair(key, QString(0, Qt::Uninitialized)));
302 } else {
303 QString value;
304 if (!qt_urlRecode(value, QStringView{delimiter + 1, pos},
305 QUrl::DecodeReserved,
306 prettyDecodedActions))
307 value = QString(delimiter + 1, pos - delimiter - 1);
308 itemList.append(std::make_pair(key, value));
309 }
310
311 if (pos != end)
312 ++pos;
313 }
314}
315
316// allow QUrlQueryPrivate to detach from null
317template <> inline QUrlQueryPrivate *
318QSharedDataPointer<QUrlQueryPrivate>::clone()
319{
320 return d ? new QUrlQueryPrivate(*d) : new QUrlQueryPrivate;
321}
322
323/*!
324 Constructs an empty QUrlQuery object. A query can be set afterwards by
325 calling setQuery() or items can be added by using addQueryItem().
326
327 \sa setQuery(), addQueryItem()
328*/
329QUrlQuery::QUrlQuery()
330 : d(nullptr)
331{
332}
333
334/*!
335 Constructs a QUrlQuery object and parses the \a queryString query string,
336 using the default query delimiters. To parse a query string using other
337 delimiters, you should first set them using setQueryDelimiters() and then
338 set the query with setQuery().
339*/
340QUrlQuery::QUrlQuery(const QString &queryString)
341 : d(queryString.isEmpty() ? nullptr : new QUrlQueryPrivate(queryString))
342{
343}
344
345/*!
346 Constructs a QUrlQuery object and parses the query string found in the \a
347 url URL, using the default query delimiters. To parse a query string using
348 other delimiters, you should first set them using setQueryDelimiters() and
349 then set the query with setQuery().
350
351 \sa QUrl::query()
352*/
353QUrlQuery::QUrlQuery(const QUrl &url)
354 : d(nullptr)
355{
356 // use internals to avoid unnecessary recoding
357 // ### FIXME: actually do it
358 if (url.hasQuery())
359 d = new QUrlQueryPrivate(url.query());
360}
361
362/*!
363 Copies the contents of the \a other QUrlQuery object, including the query
364 delimiters.
365*/
366QUrlQuery::QUrlQuery(const QUrlQuery &other)
367 : d(other.d)
368{
369}
370
371/*!
372 \fn QUrlQuery::QUrlQuery(QUrlQuery &&other) noexcept
373 \since 6.5
374 Moves the contents of the \a other QUrlQuery object, including the query
375 delimiters.
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 \memberswap{URL query instance}
391*/
392
393/*!
394 Destroys this QUrlQuery object.
395*/
396QUrlQuery::~QUrlQuery()
397{
398 // d auto-deletes
399}
400
401/*!
402 \fn bool QUrlQuery::operator==(const QUrlQuery &lhs, const QUrlQuery &rhs)
403
404 Returns \c true if QUrlQuery objects \a lhs and \a rhs contain the same
405 contents, in the same order, and use the same query delimiters.
406*/
407
408bool comparesEqual(const QUrlQuery &lhs, const QUrlQuery &rhs)
409{
410 if (lhs.d == rhs.d)
411 return true;
412 if (lhs.d && rhs.d)
413 // keep in sync with qHash(QUrlQuery):
414 return lhs.d->valueDelimiter == rhs.d->valueDelimiter &&
415 lhs.d->pairDelimiter == rhs.d->pairDelimiter &&
416 lhs.d->itemList == rhs.d->itemList;
417
418 const QUrlQueryPrivate *x = lhs.d ? lhs.d.data() : rhs.d.data();
419 return x->valueDelimiter == QUrlQuery::defaultQueryValueDelimiter() &&
420 x->pairDelimiter == QUrlQuery::defaultQueryPairDelimiter() &&
421 x->itemList.isEmpty();
422}
423
424/*!
425 \since 5.6
426 \qhashold{QUrlQuery}
427*/
428size_t qHash(const QUrlQuery &key, size_t seed) noexcept
429{
430 if (const QUrlQueryPrivate *d = key.d) {
431 // keep in sync with operator==:
432 return qHashMulti(seed, d->valueDelimiter, d->pairDelimiter, d->itemList);
433 }
434 return seed;
435}
436
437/*!
438 Returns \c true if this QUrlQuery object contains no key-value pairs, such as
439 after being default-constructed or after parsing an empty query string.
440
441 \sa setQuery(), clear()
442*/
443bool QUrlQuery::isEmpty() const
444{
445 return d ? d->itemList.isEmpty() : true;
446}
447
448/*!
449 \internal
450*/
451bool QUrlQuery::isDetached() const
452{
453 return d && d->ref.loadRelaxed() == 1;
454}
455
456/*!
457 Clears this QUrlQuery object by removing all of the key-value pairs
458 currently stored. If the query delimiters have been changed, this function
459 will leave them with their changed values.
460
461 \sa isEmpty(), setQueryDelimiters()
462*/
463void QUrlQuery::clear()
464{
465 if (d.constData())
466 d->itemList.clear();
467}
468
469/*!
470 Parses the query string in \a queryString and sets the internal items to
471 the values found there. If any delimiters have been specified with
472 setQueryDelimiters(), this function will use them instead of the default
473 delimiters to parse the string.
474*/
475void QUrlQuery::setQuery(const QString &queryString)
476{
477 d->setQuery(queryString);
478}
479
480static void recodeAndAppend(QString &to, const QString &input,
481 QUrl::ComponentFormattingOptions encoding, const ushort *tableModifications)
482{
483 if (!qt_urlRecode(to, input, encoding, tableModifications))
484 to += input;
485}
486
487/*!
488 Returns the reconstructed query string, formed from the key-value pairs
489 currently stored in this QUrlQuery object and separated by the query
490 delimiters chosen for this object. The keys and values are encoded using
491 the options given by the \a encoding parameter.
492
493 For this function, the only ambiguous delimiter is the hash ("#"), as in
494 URLs it is used to separate the query string from the fragment that may
495 follow.
496
497 The order of the key-value pairs in the returned string is exactly the same
498 as in the original query.
499
500 \sa setQuery(), QUrl::setQuery(), QUrl::fragment(), {encoding}{Encoding}
501*/
502QString QUrlQuery::query(QUrl::ComponentFormattingOptions encoding) const
503{
504 if (!d)
505 return QString();
506
507 // unlike the component encoding, for the whole query we need to modify a little:
508 // - the "#" character is unambiguous, so we encode it in EncodeDelimiters mode
509 // - the query delimiter pair must always be encoded
510
511 // start with what's always encoded
512 ushort tableActions[] = {
513 encode(d->pairDelimiter.unicode()), // 0
514 encode(d->valueDelimiter.unicode()), // 1
515 0, // 2
516 0
517 };
518 if (encoding & QUrl::EncodeDelimiters) {
519 tableActions[2] = encode('#');
520 }
521
522 QString result;
523 Map::const_iterator it = d->itemList.constBegin();
524 Map::const_iterator end = d->itemList.constEnd();
525
526 {
527 int size = 0;
528 for ( ; it != end; ++it)
529 size += it->first.size() + 1 + it->second.size() + 1;
530 result.reserve(size + size / 4);
531 }
532
533 for (it = d->itemList.constBegin(); it != end; ++it) {
534 if (!result.isEmpty())
535 result += QChar(d->pairDelimiter);
536 recodeAndAppend(result, it->first, encoding, tableActions);
537 if (!it->second.isNull()) {
538 result += QChar(d->valueDelimiter);
539 recodeAndAppend(result, it->second, encoding, tableActions);
540 }
541 }
542 return result;
543}
544
545/*!
546 Sets the characters used for delimiting between keys and values,
547 and between key-value pairs in the URL's query string. The default
548 value delimiter is '=' and the default pair delimiter is '&'.
549
550 \image qurl-querystring.png {Illustration of a URL with part after
551 question mark highlighted as query string.}
552
553 \a valueDelimiter will be used for separating keys from values,
554 and \a pairDelimiter will be used to separate key-value pairs.
555 Any occurrences of these delimiting characters in the encoded
556 representation of the keys and values of the query string are
557 percent encoded when returned in query().
558
559 If \a valueDelimiter is set to ',' and \a pairDelimiter is ';',
560 the above query string would instead be represented like this:
561
562 \snippet code/src_corelib_io_qurl.cpp 4
563
564 \note Non-standard delimiters should be chosen from among what RFC 3986 calls
565 "sub-delimiters". They are:
566
567 \snippet code/src_corelib_io_qurlquery.cpp 0
568
569 Use of other characters is not supported and may result in unexpected
570 behavior. This method does not verify that you passed a valid delimiter.
571
572 \sa queryValueDelimiter(), queryPairDelimiter()
573*/
574void QUrlQuery::setQueryDelimiters(QChar valueDelimiter, QChar pairDelimiter)
575{
576 d->valueDelimiter = valueDelimiter;
577 d->pairDelimiter = pairDelimiter;
578}
579
580/*!
581 Returns the character used to delimit between keys and values when
582 reconstructing the query string in query() or when parsing in setQuery().
583
584 \sa setQueryDelimiters(), queryPairDelimiter()
585*/
586QChar QUrlQuery::queryValueDelimiter() const
587{
588 return d ? d->valueDelimiter : defaultQueryValueDelimiter();
589}
590
591/*!
592 Returns the character used to delimit between keys-value pairs when
593 reconstructing the query string in query() or when parsing in setQuery().
594
595 \sa setQueryDelimiters(), queryValueDelimiter()
596*/
597QChar QUrlQuery::queryPairDelimiter() const
598{
599 return d ? d->pairDelimiter : defaultQueryPairDelimiter();
600}
601
602/*!
603 Sets the items in this QUrlQuery object to \a query. The order of the
604 elements in \a query is preserved.
605
606 \note This method does not treat spaces (ASCII 0x20) and plus ("+") signs
607 as the same, like HTML forms do. If you need spaces to be represented as
608 plus signs, use actual plus signs.
609
610 \note The keys and values are expected to be in percent-encoded form. This
611 function will try to recover if improperly-encoded inputs are provided, but
612 that may produce data loss. See \l{QUrlQuery#Encoding} for more information.
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. This function will
659 try to recover if an improperly-encoded input is provided, but that may
660 produce data loss. See \l{QUrlQuery#Encoding} for more information.
661
662 \sa addQueryItem(), queryItemValue()
663*/
664bool QUrlQuery::hasQueryItem(const QString &key) const
665{
666 if (!d)
667 return false;
668 return d->findKey(key) != d->itemList.constEnd();
669}
670
671/*!
672 Appends the pair \a key = \a value to the end of the query string of the
673 URL. This method does not overwrite existing items that might exist with
674 the same key.
675
676 \note This method does not treat spaces (ASCII 0x20) and plus ("+") signs
677 as the same, like HTML forms do. If you need spaces to be represented as
678 plus signs, use actual plus signs.
679
680 \note The key and value strings are expected to be in percent-encoded form.
681 This function will try to recover if improperly-encoded inputs are
682 provided, but that may produce data loss. See \l{QUrlQuery#Encoding} for
683 more information.
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. This function will
704 try to recover if an improperly-encoded input is provided, but that may
705 produce data loss. See \l{QUrlQuery#Encoding} for more information.
706
707 \sa addQueryItem(), allQueryItemValues(), {encoding}{Encoding}
708*/
709QString QUrlQuery::queryItemValue(const QString &key, QUrl::ComponentFormattingOptions encoding) const
710{
711 QString result;
712 if (d) {
713 Map::const_iterator it = d->findKey(key);
714 if (it != d->itemList.constEnd())
715 result = d->recodeToUser(it->second, encoding);
716 }
717 return result;
718}
719
720/*!
721 Returns the a list of query string values whose key is equal to \a key from
722 the URL, using the options specified in \a encoding to encode the return
723 value. If the key \a key is not found, this function returns an empty list.
724
725 \note The key is expected to be in percent-encoded form. This function will
726 try to recover if an improperly-encoded input is provided, but that may
727 produce data loss. See \l{QUrlQuery#Encoding} for more information.
728
729 \sa queryItemValue(), addQueryItem()
730*/
731QStringList QUrlQuery::allQueryItemValues(const QString &key, QUrl::ComponentFormattingOptions encoding) const
732{
733 QStringList result;
734 if (d) {
735 QString encodedKey = d->recodeFromUser(key);
736 int idx = d->findRecodedKey(encodedKey);
737 while (idx < d->itemList.size()) {
738 result << d->recodeToUser(d->itemList.at(idx).second, encoding);
739 idx = d->findRecodedKey(encodedKey, idx + 1);
740 }
741 }
742 return result;
743}
744
745/*!
746 Removes the query string pair whose key is equal to \a key from the URL. If
747 there are multiple items with a key equal to \a key, it removes the first
748 item in the order they were present in the query string or added with
749 addQueryItem().
750
751 \note The key is expected to be in percent-encoded form. This function will
752 try to recover if an improperly-encoded input is provided, but that may
753 produce data loss. See \l{QUrlQuery#Encoding} for more information.
754
755 \sa removeAllQueryItems()
756*/
757void QUrlQuery::removeQueryItem(const QString &key)
758{
759 if (d.constData()) {
760 auto *p = d.data();
761 Map::iterator it = p->findKey(key);
762 if (it != p->itemList.end())
763 p->itemList.erase(it);
764 }
765}
766
767/*!
768 Removes all the query string pairs whose key is equal to \a key
769 from the URL.
770
771 \note The key is expected to be in percent-encoded form. This function will
772 try to recover if an improperly-encoded input is provided, but that may
773 produce data loss. See \l{QUrlQuery#Encoding} for more information.
774
775 \sa removeQueryItem()
776*/
777void QUrlQuery::removeAllQueryItems(const QString &key)
778{
779 if (d.constData()) {
780 auto *p = d.data();
781 const QString encodedKey = p->recodeFromUser(key);
782 auto firstEqualsEncodedKey = [&encodedKey](const std::pair<QString, QString> &item) {
783 return item.first == encodedKey;
784 };
785 p->itemList.removeIf(firstEqualsEncodedKey);
786 }
787}
788
789/*!
790 \fn QUrlQuery::defaultQueryValueDelimiter()
791 Returns the default character for separating keys from values in the query,
792 an equal sign ("=").
793
794 \note Prior to Qt 6, this function returned QChar.
795
796 \sa setQueryDelimiters(), queryValueDelimiter(), defaultQueryPairDelimiter()
797*/
798
799/*!
800 \fn QUrlQuery::defaultQueryPairDelimiter()
801 Returns the default character for separating keys-value pairs from each
802 other, an ampersand ("&").
803
804 \note Prior to Qt 6, this function returned QChar.
805
806 \sa setQueryDelimiters(), queryPairDelimiter(), defaultQueryValueDelimiter()
807*/
808
809/*!
810 \typedef QUrlQuery::DataPtr
811 \internal
812*/
813
814/*!
815 \fn DataPtr &QUrlQuery::data_ptr()
816 \internal
817*/
818
819/*!
820 \fn QString QUrlQuery::toString(QUrl::ComponentFormattingOptions encoding = QUrl::PrettyDecoded) const
821
822 Returns this QUrlQuery as a QString. \a encoding can be used to specify the URL string encoding of the return value.
823*/
824
825/*!
826 \fn bool QUrlQuery::operator!=(const QUrlQuery &lhs, const QUrlQuery &rhs)
827
828 Returns \c true if the QUrlQuery object \a rhs is not equal to \a lhs.
829 Otherwise, returns \c false.
830
831 \sa operator==()
832*/
833QT_END_NAMESPACE
834
835#undef decode
836#undef leave
837#undef encode
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:177
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:192
#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)