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
qxcbmime.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
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:significant reason:default
4
5#include "qxcbmime.h"
6
7#include <QtGui/QImageWriter>
8#include <QtCore/QBuffer>
9#include <qdebug.h>
10
12
13using namespace Qt::StringLiterals;
14
15QXcbMime::QXcbMime()
16 : QInternalMimeData()
17{ }
18
21
22
23
24QString QXcbMime::mimeAtomToString(QXcbConnection *connection, xcb_atom_t a)
25{
26 if (a == XCB_NONE)
27 return QString();
28
29 // special cases for string type
30 if (a == XCB_ATOM_STRING
31 || a == connection->atom(QXcbAtom::AtomUTF8_STRING)
32 || a == connection->atom(QXcbAtom::AtomTEXT))
33 return "text/plain"_L1;
34
35 // special case for images
36 if (a == XCB_ATOM_PIXMAP)
37 return "image/ppm"_L1;
38
39 QByteArray atomName = connection->atomName(a);
40
41 // special cases for uris
42 if (atomName == "text/x-moz-url")
43 atomName = "text/uri-list";
44
45 return QString::fromLatin1(atomName.constData());
46}
47
48bool QXcbMime::mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeData *mimeData, QByteArray *data,
49 xcb_atom_t *atomFormat, int *dataFormat)
50{
51 if (!data)
52 return false;
53
54 bool ret = false;
55 *atomFormat = a;
56 *dataFormat = 8;
57
58 if ((a == connection->atom(QXcbAtom::AtomUTF8_STRING)
59 || a == XCB_ATOM_STRING
60 || a == connection->atom(QXcbAtom::AtomTEXT))
61 && QInternalMimeData::hasFormatHelper("text/plain"_L1, mimeData)) {
62 if (a == connection->atom(QXcbAtom::AtomUTF8_STRING)) {
63 *data = QInternalMimeData::renderDataHelper("text/plain"_L1, mimeData);
64 ret = true;
65 } else if (a == XCB_ATOM_STRING ||
66 a == connection->atom(QXcbAtom::AtomTEXT)) {
67 // ICCCM says STRING is latin1
68 *data = QString::fromUtf8(QInternalMimeData::renderDataHelper(
69 "text/plain"_L1, mimeData)).toLatin1();
70 ret = true;
71 }
72 return ret;
73 }
74
75 QString atomName = mimeAtomToString(connection, a);
76 if (QInternalMimeData::hasFormatHelper(atomName, mimeData)) {
77 *data = QInternalMimeData::renderDataHelper(atomName, mimeData);
78 // mimeAtomToString() converts "text/x-moz-url" to "text/uri-list",
79 // so QXcbConnection::atomName() has to be used.
80 if (atomName == "text/uri-list"_L1
81 && connection->atomName(a) == "text/x-moz-url") {
82 const QString mozUri = QLatin1StringView(data->split('\n').constFirst()) + u'\n';
83 data->assign({reinterpret_cast<const char *>(mozUri.data()), mozUri.size() * 2});
84 } else if (atomName == "application/x-color"_L1)
85 *dataFormat = 16;
86 ret = true;
87 } else if ((a == XCB_ATOM_PIXMAP || a == XCB_ATOM_BITMAP) && mimeData->hasImage()) {
88 ret = true;
89 } else if (atomName == "text/plain"_L1 && mimeData->hasFormat("text/uri-list"_L1)) {
90 // Return URLs also as plain text.
91 *data = QInternalMimeData::renderDataHelper(atomName, mimeData);
92 ret = true;
93 }
94 return ret;
95}
96
97QList<xcb_atom_t> QXcbMime::mimeAtomsForFormat(QXcbConnection *connection, const QString &format)
98{
99 QList<xcb_atom_t> atoms;
100 atoms.reserve(7);
101 atoms.append(connection->internAtom(format.toLatin1()));
102
103 // special cases for strings
104 if (format == "text/plain"_L1) {
105 atoms.append(connection->atom(QXcbAtom::AtomUTF8_STRING));
106 atoms.append(XCB_ATOM_STRING);
107 atoms.append(connection->atom(QXcbAtom::AtomTEXT));
108 }
109
110 // special cases for uris
111 if (format == "text/uri-list"_L1) {
112 atoms.append(connection->internAtom("text/x-moz-url"));
113 atoms.append(connection->internAtom("text/plain"));
114 }
115
116 //special cases for images
117 if (format == "image/ppm"_L1)
118 atoms.append(XCB_ATOM_PIXMAP);
119 if (format == "image/pbm"_L1)
120 atoms.append(XCB_ATOM_BITMAP);
121
122 return atoms;
123}
124
125QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &d, const QString &format,
126 QMetaType requestedType, bool hasUtf8)
127{
128 QByteArray data = d;
129 QString atomName = mimeAtomToString(connection, a);
130// qDebug() << "mimeConvertDataToFormat" << format << atomName << data;
131
132 if (hasUtf8 && atomName == format + ";charset=utf-8"_L1) {
133 if (requestedType.id() == QMetaType::QString)
134 return QString::fromUtf8(data);
135 return data;
136 }
137
138 // special cases for string types
139 if (format == "text/plain"_L1) {
140 if (data.endsWith('\0'))
141 data.chop(1);
142 if (a == connection->atom(QXcbAtom::AtomUTF8_STRING)) {
143 return QString::fromUtf8(data);
144 }
145 if (a == XCB_ATOM_STRING ||
146 a == connection->atom(QXcbAtom::AtomTEXT))
147 return QString::fromLatin1(data);
148 }
149 // If data contains UTF16 text, convert it to a string.
150 // Firefox uses UTF16 without BOM for text/x-moz-url, "text/html",
151 // Google Chrome uses UTF16 without BOM for "text/x-moz-url",
152 // UTF16 with BOM for "text/html".
153 if ((format == "text/html"_L1 || format == "text/uri-list"_L1)
154 && data.size() > 1) {
155 const quint8 byte0 = data.at(0);
156 const quint8 byte1 = data.at(1);
157 if ((byte0 == 0xff && byte1 == 0xfe) || (byte0 == 0xfe && byte1 == 0xff)
158 || (byte0 != 0 && byte1 == 0) || (byte0 == 0 && byte1 != 0)) {
159 const QStringView str(
160 reinterpret_cast<const char16_t *>(data.constData()), data.size() / 2);
161 if (!str.isNull()) {
162 if (format == "text/uri-list"_L1) {
163 const auto urls = QStringView{str}.split(u'\n');
164 QList<QVariant> list;
165 list.reserve(urls.size());
166 for (const QStringView &s : urls) {
167 const QUrl url(s.trimmed().toString());
168 if (url.isValid())
169 list.append(url);
170 }
171 // We expect "text/x-moz-url" as <url><space><title>.
172 // The atomName variable is not used because mimeAtomToString()
173 // converts "text/x-moz-url" to "text/uri-list".
174 if (!list.isEmpty() && connection->atomName(a) == "text/x-moz-url")
175 return list.constFirst();
176 return list;
177 } else {
178 return str.toString();
179 }
180 }
181 }
182 // 8 byte encoding, remove a possible 0 at the end
183 if (data.endsWith('\0'))
184 data.chop(1);
185 }
186
187 if (atomName == format)
188 return data;
189
190#if 0 // ###
191 // special case for images
192 if (format == "image/ppm"_L1) {
193 if (a == XCB_ATOM_PIXMAP && data.size() == sizeof(Pixmap)) {
194 Pixmap xpm = *((Pixmap*)data.data());
195 if (!xpm)
196 return QByteArray();
197 Window root;
198 int x;
199 int y;
200 uint width;
201 uint height;
202 uint border_width;
203 uint depth;
204
205 XGetGeometry(display, xpm, &root, &x, &y, &width, &height, &border_width, &depth);
206 XImage *ximg = XGetImage(display,xpm,x,y,width,height,AllPlanes,depth==1 ? XYPixmap : ZPixmap);
207 QImage qimg = QXlibStatic::qimageFromXImage(ximg);
208 XDestroyImage(ximg);
209
210 QImageWriter imageWriter;
211 imageWriter.setFormat("PPMRAW");
212 QBuffer buf;
213 buf.open(QIODevice::WriteOnly);
214 imageWriter.setDevice(&buf);
215 imageWriter.write(qimg);
216 return buf.buffer();
217 }
218 }
219#endif
220 return QVariant();
221}
222
223xcb_atom_t QXcbMime::mimeAtomForFormat(QXcbConnection *connection, const QString &format, QMetaType requestedType,
224 const QList<xcb_atom_t> &atoms, bool *hasUtf8)
225{
226 *hasUtf8 = false;
227
228 // find matches for string types
229 if (format == "text/plain"_L1) {
230 if (atoms.contains(connection->atom(QXcbAtom::AtomUTF8_STRING)))
231 return connection->atom(QXcbAtom::AtomUTF8_STRING);
232 if (atoms.contains(XCB_ATOM_STRING))
233 return XCB_ATOM_STRING;
234 if (atoms.contains(connection->atom(QXcbAtom::AtomTEXT)))
235 return connection->atom(QXcbAtom::AtomTEXT);
236 }
237
238 // find matches for uri types
239 if (format == "text/uri-list"_L1) {
240 xcb_atom_t a = connection->internAtom(format.toLatin1());
241 if (a && atoms.contains(a))
242 return a;
243 a = connection->internAtom("text/x-moz-url");
244 if (a && atoms.contains(a))
245 return a;
246 }
247
248 // find match for image
249 if (format == "image/ppm"_L1) {
250 if (atoms.contains(XCB_ATOM_PIXMAP))
251 return XCB_ATOM_PIXMAP;
252 }
253
254 // for string/text requests try to use a format with a well-defined charset
255 // first to avoid encoding problems
256 if (requestedType.id() == QMetaType::QString
257 && format.startsWith("text/"_L1)
258 && !format.contains("charset="_L1)) {
259
260 QString formatWithCharset = format;
261 formatWithCharset.append(";charset=utf-8"_L1);
262
263 xcb_atom_t a = connection->internAtom(std::move(formatWithCharset).toLatin1());
264 if (a && atoms.contains(a)) {
265 *hasUtf8 = true;
266 return a;
267 }
268 }
269
270 xcb_atom_t a = connection->internAtom(format.toLatin1());
271 if (a && atoms.contains(a))
272 return a;
273
274 return 0;
275}
276
277QT_END_NAMESPACE
278
279#include "moc_qxcbmime.cpp"
@ AtomUTF8_STRING
Definition qxcbatom.h:134