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
qcollator_macx.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 Aleix Pol Gonzalez <aleixpol@kde.org>
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 "qcollator_p.h"
6#include "qlocale_p.h"
7#include "qstringlist.h"
8#include "qstring.h"
9
10#include <QtCore/private/qcore_mac_p.h>
11
12#include <CoreFoundation/CoreFoundation.h>
13#include <CoreFoundation/CFLocale.h>
14
15#include <cstring>
16#include <QDebug>
17
19
21{
23 /*
24 LocaleRefFromLocaleString() will accept "POSIX" as the locale name, but
25 the locale it produces (named "pos") doesn't implement the [A-Z] < [a-z]
26 behavior we expect of the C locale. We can use QStringView to get round
27 that for collation, but this leaves no way to do a sort key.
28 */
29 if (isC())
30 return;
31
32 LocaleRef localeRef;
33 OSStatus status =
34 LocaleRefFromLocaleString(QLocalePrivate::get(locale)->bcp47Name().constData(), &localeRef);
35 if (status != 0)
36 qCWarning(lcQCollator, "Couldn't initialize the locale (%d)", int(status));
37
38 UInt32 collationOptions = 0;
39 // enable normalization by default
40 collationOptions |= kUCCollateComposeInsensitiveMask;
41
42 if (options.testFlag(Opt::CaseInsensitive))
43 collationOptions |= kUCCollateCaseInsensitiveMask;
44 if (options.testFlag(Opt::NumericSort))
45 collationOptions |= kUCCollateDigitsAsNumberMask | kUCCollateDigitsOverrideMask;
46 if (!options.testFlag(Opt::IgnorePunctuation))
47 collationOptions |= kUCCollatePunctuationSignificantMask;
48 if (options.testFlag(Opt::DiacriticInsensitive))
49 collationOptions |= kUCCollateDiacritInsensitiveMask;
50 if (options.testFlag(Opt::WidthInsensitive))
51 collationOptions |= kUCCollateWidthInsensitiveMask;
52
53 status = UCCreateCollator(localeRef, 0, collationOptions, &collator);
54 if (status != 0)
55 qCWarning(lcQCollator, "Couldn't initialize the collator (%d)", int(status));
56
57 dirty = false;
58}
59
61{
62 if (collator)
63 UCDisposeCollator(&collator);
64 collator = 0;
65}
66
67int QCollator::compare(QStringView s1, QStringView s2) const
68{
69 if (!s1.size())
70 return s2.size() ? -1 : 0;
71 if (!s2.size())
72 return +1;
73
74 if (!d)
75 d = new QCollatorPrivate(QLocale().collation());
76
77 d->ensureInitialized();
78
79 if (!d->collator)
80 return s1.compare(s2, caseSensitivity());
81
82 SInt32 result;
83 Boolean equivalent;
84 UCCompareText(d->collator,
85 reinterpret_cast<const UniChar *>(s1.data()), s1.size(),
86 reinterpret_cast<const UniChar *>(s2.data()), s2.size(),
87 &equivalent,
88 &result);
89 if (equivalent)
90 return 0;
91 return result < 0 ? -1 : 1;
92}
93
94QCollatorSortKey QCollator::sortKey(const QString &string) const
95{
96 if (!d)
97 d = new QCollatorPrivate(QLocale().collation());
98
99 d->ensureInitialized();
100
101 QList<UCCollationValue> ret;
102 if (!d->collator) {
103 // What should (or even *can*) we do here ? (See init()'s comment.)
104 qCWarning(lcQCollator, "QCollator doesn't support sort keys for the C locale on Darwin");
105 return QCollatorPrivate::sortKeyFromData(std::move(ret));
106 }
107
108 auto text = reinterpret_cast<const UniChar *>(string.constData());
109 // Documentation recommends having it 5 times as big as the input
110 ret.resizeForOverwrite(string.size() * 5);
111 ItemCount actualSize;
112 int status = UCGetCollationKey(d->collator, text, string.size(),
113 ret.size(), &actualSize, ret.data());
114
115 ret.resize(actualSize + 1);
116 if (status == kUCOutputBufferTooSmall) {
117 status = UCGetCollationKey(d->collator, text, string.size(),
118 ret.size(), &actualSize, ret.data());
119 Q_ASSERT(status != kUCOutputBufferTooSmall);
120 Q_ASSERT(ret.size() == qsizetype(actualSize + 1));
121 }
122 ret[actualSize] = 0;
123 return QCollatorPrivate::sortKeyFromData(std::move(ret));
124}
125
126int QCollatorSortKey::compare(const QCollatorSortKey &key) const noexcept
127{
128 SInt32 order;
129 UCCompareCollationKeys(d->m_key.data(), d->m_key.size(),
130 key.d->m_key.data(), key.d->m_key.size(),
131 nullptr, &order);
132 return order;
133}
134
135QT_END_NAMESPACE
bool isC() const
Definition qcollator_p.h:85
CollatorType collator
Definition qcollator_p.h:78
static const QLocalePrivate * get(const QLocale &l)
Definition qlocale_p.h:697