Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwindowsmimeregistry.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 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
5#include "qwindowscontext.h"
6
7#include <QtGui/private/qinternalmimedata_p.h>
8#include <QtCore/qbytearraymatcher.h>
9#include <QtCore/qmap.h>
10#include <QtCore/qurl.h>
11#include <QtCore/qdir.h>
12#include <QtCore/qdebug.h>
13#include <QtCore/qbuffer.h>
14#include <QtGui/qimagereader.h>
15#include <QtGui/qimagewriter.h>
16
17#include <shlobj.h>
18#include <algorithm>
19
21
22using namespace Qt::StringLiterals;
23
24/* The MSVC compilers allows multi-byte characters, that has the behavior of
25 * that each character gets shifted into position. 0x73524742 below is for MSVC
26 * equivalent to doing 'sRGB', but this does of course not work
27 * on conformant C++ compilers. */
28#define BMP_LCS_sRGB 0x73524742
29#define BMP_LCS_GM_IMAGES 0x00000004L
30
31struct _CIEXYZ {
33};
34
38
65
66static const char dibFormatC[] = "dib";
67
68static inline QByteArray msgConversionError(const char *func, const char *format)
69{
70 QByteArray msg = func;
71 msg += ": Unable to convert DIB image. The image converter plugin for '";
72 msg += format;
73 msg += "' is not available. Available formats: ";
75 for (const QByteArray &af : formats) {
76 msg += af;
77 msg += ' ';
78 }
79 return msg;
80}
81
82static inline bool readDib(QBuffer &buffer, QImage &img)
83{
85 if (!reader.canRead()) {
86 qWarning("%s", msgConversionError(__FUNCTION__, dibFormatC).constData());
87 return false;
88 }
89 img = reader.read();
90 return true;
91}
92
94{
99 if (!writer.canWrite()) {
100 qWarning("%s", msgConversionError(__FUNCTION__, dibFormatC).constData());
101 return ba;
102 }
103 if (!writer.write(img))
104 ba.clear();
105 return ba;
106}
107
109{
110 QIODevice* d = s.device();
111 if (!d->isWritable())
112 return false;
113
114 //depth will be always 32
115 qsizetype bpl_bmp = qsizetype(image.width()) * 4;
116 qsizetype size = bpl_bmp * image.height();
117 if (qsizetype(DWORD(size)) != size)
118 return false;
119
121 ZeroMemory(&bi, sizeof(bi));
122 bi.bV5Size = sizeof(BMP_BITMAPV5HEADER);
123 bi.bV5Width = image.width();
124 bi.bV5Height = image.height();
125 bi.bV5Planes = 1;
126 bi.bV5BitCount = 32;
127 bi.bV5Compression = BI_BITFIELDS;
128 bi.bV5SizeImage = DWORD(bpl_bmp * image.height());
129 bi.bV5XPelsPerMeter = 0;
130 bi.bV5YPelsPerMeter = 0;
131 bi.bV5ClrUsed = 0;
132 bi.bV5ClrImportant = 0;
133 bi.bV5BlueMask = 0x000000ff;
134 bi.bV5GreenMask = 0x0000ff00;
135 bi.bV5RedMask = 0x00ff0000;
136 bi.bV5AlphaMask = 0xff000000;
137 bi.bV5CSType = BMP_LCS_sRGB; //LCS_sRGB
138 bi.bV5Intent = BMP_LCS_GM_IMAGES; //LCS_GM_IMAGES
139
140 d->write(reinterpret_cast<const char*>(&bi), bi.bV5Size);
141 if (s.status() != QDataStream::Ok)
142 return false;
143
144 d->write(reinterpret_cast<const char *>(&bi.bV5RedMask), sizeof(bi.bV5RedMask));
145 if (s.status() != QDataStream::Ok)
146 return false;
147
148 d->write(reinterpret_cast<const char *>(&bi.bV5GreenMask), sizeof(bi.bV5GreenMask));
149 if (s.status() != QDataStream::Ok)
150 return false;
151
152 d->write(reinterpret_cast<const char *>(&bi.bV5BlueMask), sizeof(bi.bV5BlueMask));
153 if (s.status() != QDataStream::Ok)
154 return false;
155
156 if (image.format() != QImage::Format_ARGB32)
157 image = std::move(image).convertToFormat(QImage::Format_ARGB32);
158
159 auto *buf = new uchar[bpl_bmp];
160
161 memset(buf, 0, size_t(bpl_bmp));
162 for (int y=image.height()-1; y>=0; y--) {
163 // write the image bits
164 const QRgb *p = reinterpret_cast<const QRgb *>(image.constScanLine(y));
165 const QRgb *end = p + image.width();
166 uchar *b = buf;
167 while (p < end) {
168 int alpha = qAlpha(*p);
169 if (alpha) {
170 *b++ = uchar(qBlue(*p));
171 *b++ = uchar(qGreen(*p));
172 *b++ = uchar(qRed(*p));
173 } else {
174 //white for fully transparent pixels.
175 *b++ = 0xff;
176 *b++ = 0xff;
177 *b++ = 0xff;
178 }
179 *b++ = uchar(alpha);
180 p++;
181 }
182 d->write(reinterpret_cast<const char *>(buf), bpl_bmp);
183 if (s.status() != QDataStream::Ok) {
184 delete[] buf;
185 return false;
186 }
187 }
188 delete[] buf;
189 return true;
190}
191
192// helpers for using global memory
193
194static int getCf(const FORMATETC &formatetc)
195{
196 return formatetc.cfFormat;
197}
198
199static FORMATETC setCf(int cf)
200{
201 FORMATETC formatetc;
202 formatetc.cfFormat = CLIPFORMAT(cf);
203 formatetc.dwAspect = DVASPECT_CONTENT;
204 formatetc.lindex = -1;
205 formatetc.ptd = nullptr;
206 formatetc.tymed = TYMED_HGLOBAL;
207 return formatetc;
208}
209
210static bool setData(const QByteArray &data, STGMEDIUM *pmedium)
211{
212 HGLOBAL hData = GlobalAlloc(0, SIZE_T(data.size()));
213 if (!hData)
214 return false;
215
216 void *out = GlobalLock(hData);
217 memcpy(out, data.data(), size_t(data.size()));
218 GlobalUnlock(hData);
219 pmedium->tymed = TYMED_HGLOBAL;
220 pmedium->hGlobal = hData;
221 pmedium->pUnkForRelease = nullptr;
222 return true;
223}
224
225static QByteArray getData(int cf, IDataObject *pDataObj, int lindex = -1)
226{
228 FORMATETC formatetc = setCf(cf);
229 formatetc.lindex = lindex;
230 STGMEDIUM s;
231 if (pDataObj->GetData(&formatetc, &s) == S_OK) {
232 const void *val = GlobalLock(s.hGlobal);
233 data = QByteArray::fromRawData(reinterpret_cast<const char *>(val), int(GlobalSize(s.hGlobal)));
234 data.detach();
235 GlobalUnlock(s.hGlobal);
236 ReleaseStgMedium(&s);
237 } else {
238 //Try reading IStream data
239 formatetc.tymed = TYMED_ISTREAM;
240 if (pDataObj->GetData(&formatetc, &s) == S_OK) {
241 char szBuffer[4096];
242 ULONG actualRead = 0;
243 LARGE_INTEGER pos = {{0, 0}};
244 //Move to front (can fail depending on the data model implemented)
245 HRESULT hr = s.pstm->Seek(pos, STREAM_SEEK_SET, nullptr);
246 while(SUCCEEDED(hr)){
247 hr = s.pstm->Read(szBuffer, sizeof(szBuffer), &actualRead);
248 if (SUCCEEDED(hr) && actualRead > 0) {
249 data += QByteArray::fromRawData(szBuffer, int(actualRead));
250 }
251 if (actualRead != sizeof(szBuffer))
252 break;
253 }
254 data.detach();
255 ReleaseStgMedium(&s);
256 }
257 }
258 return data;
259}
260
261static bool canGetData(int cf, IDataObject * pDataObj)
262{
263 FORMATETC formatetc = setCf(cf);
264 if (pDataObj->QueryGetData(&formatetc) != S_OK){
265 formatetc.tymed = TYMED_ISTREAM;
266 return pDataObj->QueryGetData(&formatetc) == S_OK;
267 }
268 return true;
269}
270
271#ifndef QT_NO_DEBUG_STREAM
273{
274 QDebugStateSaver saver(d);
275 d.nospace();
276 d << "FORMATETC(cfFormat=" << tc.cfFormat << ' ';
277 switch (tc.cfFormat) {
278 case CF_TEXT:
279 d << "CF_TEXT";
280 break;
281 case CF_BITMAP:
282 d << "CF_BITMAP";
283 break;
284 case CF_TIFF:
285 d << "CF_TIFF";
286 break;
287 case CF_OEMTEXT:
288 d << "CF_OEMTEXT";
289 break;
290 case CF_DIB:
291 d << "CF_DIB";
292 break;
293 case CF_DIBV5:
294 d << "CF_DIBV5";
295 break;
296 case CF_UNICODETEXT:
297 d << "CF_UNICODETEXT";
298 break;
299 case CF_ENHMETAFILE:
300 d << "CF_ENHMETAFILE";
301 break;
302 default:
304 break;
305 }
306 d << ", dwAspect=" << tc.dwAspect << ", lindex=" << tc.lindex
307 << ", tymed=" << tc.tymed << ", ptd=" << tc.ptd << ')';
308 return d;
309}
310
311QDebug operator<<(QDebug d, IDataObject *dataObj)
312{
313 QDebugStateSaver saver(d);
314 d.nospace();
315 d.noquote();
316 d << "IDataObject(";
317 if (dataObj) { // Output formats contained in IDataObject.
318 IEnumFORMATETC *enumFormatEtc;
319 if (SUCCEEDED(dataObj->EnumFormatEtc(DATADIR_GET, &enumFormatEtc)) && enumFormatEtc) {
320 FORMATETC formatEtc[1];
321 ULONG fetched;
322 if (SUCCEEDED(enumFormatEtc->Reset())) {
323 while (SUCCEEDED(enumFormatEtc->Next(1, formatEtc, &fetched)) && fetched)
324 d << formatEtc[0] << ',';
325 enumFormatEtc->Release();
326 }
327 }
328 } else {
329 d << '0';
330 }
331 d << ')';
332 return d;
333}
334#endif // !QT_NO_DEBUG_STREAM
335
337{
338public:
339 bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
340 QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QMetaType preferredType) const override;
341 QString mimeForFormat(const FORMATETC &formatetc) const override;
342 bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
343 bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const override;
344 QList<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
345};
346
348{
349 int cf = getCf(formatetc);
350 return (cf == CF_UNICODETEXT || (cf == CF_TEXT && GetACP() != CP_UTF8)) && mimeData->hasText();
351}
352
353/*
354text/plain is defined as using CRLF, but so many programs don't,
355and programmers just look for '\n' in strings.
356Windows really needs CRLF, so we ensure it here.
357*/
358bool QWindowsMimeText::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const
359{
360 if (canConvertFromMime(formatetc, mimeData)) {
362 int cf = getCf(formatetc);
363 if (cf == CF_TEXT) {
365 // Anticipate required space for CRLFs at 1/40
366 int maxsize=data.size()+data.size()/40+3;
367 QByteArray r(maxsize, '\0');
368 char* o = r.data();
369 const char* d = data.data();
370 const int s = data.size();
371 bool cr=false;
372 int j=0;
373 for (int i=0; i<s; i++) {
374 char c = d[i];
375 if (c=='\r')
376 cr=true;
377 else {
378 if (c=='\n') {
379 if (!cr)
380 o[j++]='\r';
381 }
382 cr=false;
383 }
384 o[j++]=c;
385 if (j+3 >= maxsize) {
386 maxsize += maxsize/4;
387 r.resize(maxsize);
388 o = r.data();
389 }
390 }
391 o[j]=0;
392 return setData(r, pmedium);
393 }
394 if (cf == CF_UNICODETEXT) {
396 const QChar *u = str.unicode();
397 QString res;
398 const int s = str.length();
399 int maxsize = s + s/40 + 3;
400 res.resize(maxsize);
401 int ri = 0;
402 bool cr = false;
403 for (int i=0; i < s; ++i) {
404 if (*u == u'\r')
405 cr = true;
406 else {
407 if (*u == u'\n' && !cr)
408 res[ri++] = u'\r';
409 cr = false;
410 }
411 res[ri++] = *u;
412 if (ri+3 >= maxsize) {
413 maxsize += maxsize/4;
414 res.resize(maxsize);
415 }
416 ++u;
417 }
418 res.truncate(ri);
419 const int byteLength = res.length() * int(sizeof(ushort));
420 QByteArray r(byteLength + 2, '\0');
421 memcpy(r.data(), res.unicode(), size_t(byteLength));
422 r[byteLength] = 0;
423 r[byteLength+1] = 0;
424 return setData(r, pmedium);
425 }
426 }
427 return false;
428}
429
430bool QWindowsMimeText::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
431{
432 return mimeType.startsWith(u"text/plain")
433 && (canGetData(CF_UNICODETEXT, pDataObj)
434 || canGetData(CF_TEXT, pDataObj));
435}
436
438{
439 int cf = getCf(formatetc);
440 if (cf == CF_UNICODETEXT || cf == CF_TEXT)
441 return u"text/plain"_s;
442 return QString();
443}
444
445
447{
448 QList<FORMATETC> formatics;
449 if (mimeType.startsWith(u"text/plain") && mimeData->hasText()) {
450 formatics += setCf(CF_UNICODETEXT);
451 if (GetACP() != CP_UTF8)
452 formatics += setCf(CF_TEXT);
453 }
454 return formatics;
455}
456
457QVariant QWindowsMimeText::convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QMetaType preferredType) const
458{
460
461 if (canConvertToMime(mime, pDataObj)) {
462 QString str;
463 QByteArray data = getData(CF_UNICODETEXT, pDataObj);
464 if (!data.isEmpty()) {
465 str = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData()));
466 str.replace("\r\n"_L1, "\n"_L1);
467 } else {
468 data = getData(CF_TEXT, pDataObj);
469 if (!data.isEmpty()) {
470 const char* d = data.data();
471 const unsigned s = unsigned(qstrlen(d));
472 QByteArray r(data.size()+1, '\0');
473 char* o = r.data();
474 int j=0;
475 for (unsigned i = 0; i < s; ++i) {
476 char c = d[i];
477 if (c!='\r')
478 o[j++]=c;
479 }
480 o[j]=0;
482 }
483 }
484 if (preferredType.id() == QMetaType::QString)
485 ret = str;
486 else
487 ret = std::move(str).toUtf8();
488 }
489 qCDebug(lcQpaMime) << __FUNCTION__ << ret;
490 return ret;
491}
492
494{
495public:
497 bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
498 QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QMetaType preferredType) const override;
499 QString mimeForFormat(const FORMATETC &formatetc) const override;
500 bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
501 bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const override;
502 QList<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
503private:
504 int CF_INETURL_W; // wide char version
505 int CF_INETURL;
506};
507
509{
510 CF_INETURL_W = registerMimeType(u"UniformResourceLocatorW"_s);
511 CF_INETURL = registerMimeType(u"UniformResourceLocator"_s);
512}
513
515{
516 if (mimeData->hasUrls() && getCf(formatetc) == CF_HDROP) {
517 const auto urls = mimeData->urls();
518 for (const QUrl &url : urls) {
519 if (url.isLocalFile())
520 return true;
521 }
522 }
523 return (getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL) && mimeData->hasUrls();
524}
525
526bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const
527{
528 if (canConvertFromMime(formatetc, mimeData)) {
529 if (getCf(formatetc) == CF_HDROP) {
530 const auto &urls = mimeData->urls();
532 size_t size = sizeof(DROPFILES) + 2;
533 for (const QUrl &url : urls) {
535 if (!fn.isEmpty()) {
536 size += sizeof(ushort) * size_t(fn.length() + 1);
537 fileNames.append(fn);
538 }
539 }
540
541 QByteArray result(int(size), '\0');
542 auto* d = reinterpret_cast<DROPFILES *>(result.data());
543 d->pFiles = sizeof(DROPFILES);
544 GetCursorPos(&d->pt); // try
545 d->fNC = true;
546 char *files = (reinterpret_cast<char*>(d)) + d->pFiles;
547
548 d->fWide = true;
549 auto *f = reinterpret_cast<wchar_t *>(files);
550 for (int i=0; i<fileNames.size(); i++) {
551 const auto l = size_t(fileNames.at(i).length());
552 memcpy(f, fileNames.at(i).data(), l * sizeof(ushort));
553 f += l;
554 *f++ = 0;
555 }
556 *f = 0;
557
558 return setData(result, pmedium);
559 }
560 if (getCf(formatetc) == CF_INETURL_W) {
561 const auto urls = mimeData->urls();
563 if (!urls.isEmpty()) {
564 const QString url = urls.at(0).toString();
565 result = QByteArray(reinterpret_cast<const char *>(url.data()),
566 url.length() * int(sizeof(ushort)));
567 }
568 result.append('\0');
569 result.append('\0');
570 return setData(result, pmedium);
571 }
572 if (getCf(formatetc) == CF_INETURL) {
573 const auto urls = mimeData->urls();
575 if (!urls.isEmpty())
576 result = urls.at(0).toString().toLocal8Bit();
577 return setData(result, pmedium);
578 }
579 }
580
581 return false;
582}
583
584bool QWindowsMimeURI::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
585{
586 return mimeType == u"text/uri-list"
587 && (canGetData(CF_HDROP, pDataObj) || canGetData(CF_INETURL_W, pDataObj) || canGetData(CF_INETURL, pDataObj));
588}
589
591{
593 if (getCf(formatetc) == CF_HDROP || getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL)
594 format = u"text/uri-list"_s;
595 return format;
596}
597
599{
600 QList<FORMATETC> formatics;
601 if (mimeType == u"text/uri-list") {
602 if (canConvertFromMime(setCf(CF_HDROP), mimeData))
603 formatics += setCf(CF_HDROP);
604 if (canConvertFromMime(setCf(CF_INETURL_W), mimeData))
605 formatics += setCf(CF_INETURL_W);
606 if (canConvertFromMime(setCf(CF_INETURL), mimeData))
607 formatics += setCf(CF_INETURL);
608 }
609 return formatics;
610}
611
612QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pDataObj, QMetaType preferredType) const
613{
614 if (mimeType == u"text/uri-list") {
615 if (canGetData(CF_HDROP, pDataObj)) {
616 QList<QVariant> urls;
617
618 QByteArray data = getData(CF_HDROP, pDataObj);
619 if (data.isEmpty())
620 return QVariant();
621
622 const auto *hdrop = reinterpret_cast<const DROPFILES *>(data.constData());
623 if (hdrop->fWide) {
624 const auto *filesw = reinterpret_cast<const wchar_t *>(data.constData() + hdrop->pFiles);
625 int i = 0;
626 while (filesw[i]) {
627 QString fileurl = QString::fromWCharArray(filesw + i);
628 urls += QUrl::fromLocalFile(fileurl);
629 i += fileurl.length()+1;
630 }
631 } else {
632 const char* files = reinterpret_cast<const char *>(data.constData() + hdrop->pFiles);
633 int i=0;
634 while (files[i]) {
636 i += int(strlen(files+i))+1;
637 }
638 }
639
640 if (preferredType.id() == QMetaType::QUrl && urls.size() == 1)
641 return urls.at(0);
642 if (!urls.isEmpty())
643 return urls;
644 } else if (canGetData(CF_INETURL_W, pDataObj)) {
645 QByteArray data = getData(CF_INETURL_W, pDataObj);
646 if (data.isEmpty())
647 return QVariant();
648 return QUrl(QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData())));
649 } else if (canGetData(CF_INETURL, pDataObj)) {
650 QByteArray data = getData(CF_INETURL, pDataObj);
651 if (data.isEmpty())
652 return QVariant();
653 return QUrl(QString::fromLocal8Bit(data.constData()));
654 }
655 }
656 return QVariant();
657}
658
660{
661public:
663
664 // for converting from Qt
665 bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
666 bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override;
667 QList<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
668
669 // for converting to Qt
670 bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
671 QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const override;
672 QString mimeForFormat(const FORMATETC &formatetc) const override;
673
674private:
675 int CF_HTML;
676};
677
679{
680 CF_HTML = registerMimeType(u"HTML Format"_s);
681}
682
684{
685 QList<FORMATETC> formatetcs;
686 if (mimeType == u"text/html" && (!mimeData->html().isEmpty()))
687 formatetcs += setCf(CF_HTML);
688 return formatetcs;
689}
690
692{
693 if (getCf(formatetc) == CF_HTML)
694 return u"text/html"_s;
695 return QString();
696}
697
698bool QWindowsMimeHtml::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
699{
700 return mimeType == u"text/html" && canGetData(CF_HTML, pDataObj);
701}
702
703
705{
706 return getCf(formatetc) == CF_HTML && (!mimeData->html().isEmpty());
707}
708
709/*
710The windows HTML clipboard format is as follows (xxxxxxxxxx is a 10 integer number giving the positions
711in bytes). Charset used is mostly utf8, but can be different, ie. we have to look for the <meta> charset tag
712
713 Version: 1.0
714 StartHTML:xxxxxxxxxx
715 EndHTML:xxxxxxxxxx
716 StartFragment:xxxxxxxxxx
717 EndFragment:xxxxxxxxxx
718 ...html...
719
720*/
721QVariant QWindowsMimeHtml::convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const
722{
723 Q_UNUSED(preferredType);
725 if (canConvertToMime(mime, pDataObj)) {
726 QByteArray html = getData(CF_HTML, pDataObj);
727 static constexpr auto startMatcher = qMakeStaticByteArrayMatcher("StartHTML:");
728 static constexpr auto endMatcher = qMakeStaticByteArrayMatcher("EndHTML:");
729 qCDebug(lcQpaMime) << __FUNCTION__ << "raw:" << html;
730 int start = startMatcher.indexIn(html);
731 int end = endMatcher.indexIn(html);
732
733 if (start != -1) {
734 int startOffset = start + 10;
735 int i = startOffset;
736 while (html.at(i) != '\r' && html.at(i) != '\n')
737 ++i;
738 QByteArray bytecount = html.mid(startOffset, i - startOffset);
739 start = bytecount.toInt();
740 }
741
742 if (end != -1) {
743 int endOffset = end + 8;
744 int i = endOffset ;
745 while (html.at(i) != '\r' && html.at(i) != '\n')
746 ++i;
747 QByteArray bytecount = html.mid(endOffset , i - endOffset);
748 end = bytecount.toInt();
749 }
750
751 if (end > start && start > 0) {
752 html = html.mid(start, end - start);
753 html.replace('\r', "");
755 }
756 }
757 return result;
758}
759
760bool QWindowsMimeHtml::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
761{
762 if (canConvertFromMime(formatetc, mimeData)) {
765 "Version:1.0\r\n" // 0-12
766 "StartHTML:0000000107\r\n" // 13-35
767 "EndHTML:0000000000\r\n" // 36-55
768 "StartFragment:0000000000\r\n" // 56-81
769 "EndFragment:0000000000\r\n\r\n"; // 82-107
770
771 static constexpr auto startFragmentMatcher = qMakeStaticByteArrayMatcher("<!--StartFragment-->");
772 static constexpr auto endFragmentMatcher = qMakeStaticByteArrayMatcher("<!--EndFragment-->");
773
774 if (startFragmentMatcher.indexIn(data) == -1)
775 result += "<!--StartFragment-->";
776 result += data;
777 if (endFragmentMatcher.indexIn(data) == -1)
778 result += "<!--EndFragment-->";
779
780 // set the correct number for EndHTML
782 memcpy(reinterpret_cast<char *>(result.data() + 53 - pos.length()), pos.constData(), size_t(pos.length()));
783
784 // set correct numbers for StartFragment and EndFragment
785 pos = QByteArray::number(startFragmentMatcher.indexIn(result) + 20);
786 memcpy(reinterpret_cast<char *>(result.data() + 79 - pos.length()), pos.constData(), size_t(pos.length()));
787 pos = QByteArray::number(endFragmentMatcher.indexIn(result));
788 memcpy(reinterpret_cast<char *>(result.data() + 103 - pos.length()), pos.constData(), size_t(pos.length()));
789
790 return setData(result, pmedium);
791 }
792 return false;
793}
794
795
796#ifndef QT_NO_IMAGEFORMAT_BMP
798{
799public:
801 // for converting from Qt
802 bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
803 bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override;
804 QList<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
805
806 // for converting to Qt
807 bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
808 QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const override;
809 QString mimeForFormat(const FORMATETC &formatetc) const override;
810private:
811 bool hasOriginalDIBV5(IDataObject *pDataObj) const;
812 UINT CF_PNG;
813};
814
816{
817 CF_PNG = RegisterClipboardFormat(L"PNG");
818}
819
821{
822 QList<FORMATETC> formatetcs;
823 if (mimeData->hasImage() && mimeType == u"application/x-qt-image") {
824 //add DIBV5 if image has alpha channel. Do not add CF_PNG here as it will confuse MS Office (QTBUG47656).
825 auto image = qvariant_cast<QImage>(mimeData->imageData());
826 if (!image.isNull() && image.hasAlphaChannel())
827 formatetcs += setCf(CF_DIBV5);
828 formatetcs += setCf(CF_DIB);
829 }
830 if (!formatetcs.isEmpty())
831 qCDebug(lcQpaMime) << __FUNCTION__ << mimeType << formatetcs;
832 return formatetcs;
833}
834
836{
837 int cf = getCf(formatetc);
838 if (cf == CF_DIB || cf == CF_DIBV5 || cf == int(CF_PNG))
839 return u"application/x-qt-image"_s;
840 return QString();
841}
842
843bool QWindowsMimeImage::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
844{
845 return mimeType == u"application/x-qt-image"
846 && (canGetData(CF_DIB, pDataObj) || canGetData(CF_PNG, pDataObj));
847}
848
850{
851 int cf = getCf(formatetc);
852 if (!mimeData->hasImage())
853 return false;
854 const QImage image = qvariant_cast<QImage>(mimeData->imageData());
855 if (image.isNull())
856 return false;
857 // QTBUG-64322: Use PNG only for transparent images as otherwise MS PowerPoint
858 // cannot handle it.
859 return cf == CF_DIBV5 || cf == CF_DIB
860 || (cf == int(CF_PNG) && image.hasAlphaChannel());
861}
862
863bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
864{
865 int cf = getCf(formatetc);
866 if ((cf == CF_DIB || cf == CF_DIBV5 || cf == int(CF_PNG)) && mimeData->hasImage()) {
867 auto img = qvariant_cast<QImage>(mimeData->imageData());
868 if (img.isNull())
869 return false;
871 if (cf == CF_DIB) {
872 if (img.format() > QImage::Format_ARGB32)
873 img = std::move(img).convertToFormat(QImage::Format_RGB32);
874 const QByteArray ba = writeDib(img);
875 if (!ba.isEmpty())
876 return setData(ba, pmedium);
877 } else if (cf == int(CF_PNG)) {
878 QBuffer buffer(&ba);
879 const bool written = buffer.open(QIODevice::WriteOnly) && img.save(&buffer, "PNG");
880 buffer.close();
881 if (written)
882 return setData(ba, pmedium);
883 } else {
885 s.setByteOrder(QDataStream::LittleEndian);// Intel byte order ####
886 if (qt_write_dibv5(s, std::move(img)))
887 return setData(ba, pmedium);
888 }
889 }
890 return false;
891}
892
893bool QWindowsMimeImage::hasOriginalDIBV5(IDataObject *pDataObj) const
894{
895 bool isSynthesized = true;
896 IEnumFORMATETC *pEnum = nullptr;
897 HRESULT res = pDataObj->EnumFormatEtc(1, &pEnum);
898 if (res == S_OK && pEnum) {
899 FORMATETC fc;
900 while ((res = pEnum->Next(1, &fc, nullptr)) == S_OK) {
901 if (fc.ptd)
902 CoTaskMemFree(fc.ptd);
903 if (fc.cfFormat == CF_DIB)
904 break;
905 if (fc.cfFormat == CF_DIBV5) {
906 isSynthesized = false;
907 break;
908 }
909 }
910 pEnum->Release();
911 }
912 return !isSynthesized;
913}
914
915QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *pDataObj, QMetaType preferredType) const
916{
917 Q_UNUSED(preferredType);
919 if (mimeType != u"application/x-qt-image")
920 return result;
921 // Try to convert from DIBV5 as it is the most widespread format that supports transparency,
922 // but avoid synthesizing it, as that typically loses transparency, e.g. from Office
923 const bool canGetDibV5 = canGetData(CF_DIBV5, pDataObj);
924 const bool hasOrigDibV5 = canGetDibV5 ? hasOriginalDIBV5(pDataObj) : false;
925 qCDebug(lcQpaMime) << "canGetDibV5:" << canGetDibV5 << "hasOrigDibV5:" << hasOrigDibV5;
926 if (hasOrigDibV5) {
927 qCDebug(lcQpaMime) << "Decoding DIBV5";
928 QImage img;
929 QByteArray data = getData(CF_DIBV5, pDataObj);
931 if (readDib(buffer, img))
932 return img;
933 }
934 //PNG, MS Office place this (undocumented)
935 if (canGetData(CF_PNG, pDataObj)) {
936 qCDebug(lcQpaMime) << "Decoding PNG";
937 QImage img;
938 QByteArray data = getData(CF_PNG, pDataObj);
939 if (img.loadFromData(data, "PNG")) {
940 return img;
941 }
942 }
943 //Fallback to DIB
944 if (canGetData(CF_DIB, pDataObj)) {
945 qCDebug(lcQpaMime) << "Decoding DIB";
946 QImage img;
947 QByteArray data = getData(CF_DIBV5, pDataObj);
949 if (readDib(buffer, img))
950 return img;
951 }
952 // Failed
953 return result;
954}
955#endif
956
958{
959public:
961
962 // for converting from Qt
963 bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
964 bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override;
965 QList<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
966
967 // for converting to Qt
968 bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
969 QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const override;
970 QString mimeForFormat(const FORMATETC &formatetc) const override;
971
972private:
973 QMap<int, QString> outFormats;
974 QMap<int, QString> inFormats;
975};
976
979{
980 outFormats.insert(registerMimeType(u"application/x-color"_s), u"application/x-color"_s);
981 inFormats.insert(registerMimeType(u"application/x-color"_s), u"application/x-color"_s);
982}
983
985{
986 // really check
987 return formatetc.tymed & TYMED_HGLOBAL
988 && outFormats.contains(formatetc.cfFormat)
989 && mimeData->formats().contains(outFormats.value(formatetc.cfFormat));
990}
991
992bool QBuiltInMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
993{
994 if (canConvertFromMime(formatetc, mimeData)) {
996 if (outFormats.value(getCf(formatetc)) == u"text/html") {
997 // text/html is in wide chars on windows (compatible with mozillia)
998 QString html = mimeData->html();
999 // same code as in the text converter up above
1000 const QChar *u = html.unicode();
1001 QString res;
1002 const int s = html.length();
1003 int maxsize = s + s/40 + 3;
1004 res.resize(maxsize);
1005 int ri = 0;
1006 bool cr = false;
1007 for (int i=0; i < s; ++i) {
1008 if (*u == u'\r')
1009 cr = true;
1010 else {
1011 if (*u == u'\n' && !cr)
1012 res[ri++] = u'\r';
1013 cr = false;
1014 }
1015 res[ri++] = *u;
1016 if (ri+3 >= maxsize) {
1017 maxsize += maxsize/4;
1018 res.resize(maxsize);
1019 }
1020 ++u;
1021 }
1022 res.truncate(ri);
1023 const int byteLength = res.length() * int(sizeof(ushort));
1024 QByteArray r(byteLength + 2, '\0');
1025 memcpy(r.data(), res.unicode(), size_t(byteLength));
1026 r[byteLength] = 0;
1027 r[byteLength+1] = 0;
1028 data = r;
1029 } else {
1030#if QT_CONFIG(draganddrop)
1031 data = QInternalMimeData::renderDataHelper(outFormats.value(getCf(formatetc)), mimeData);
1032#endif // QT_CONFIG(draganddrop)
1033 }
1034 return setData(data, pmedium);
1035 }
1036 return false;
1037}
1038
1040{
1041 QList<FORMATETC> formatetcs;
1042 const auto mit = std::find(outFormats.cbegin(), outFormats.cend(), mimeType);
1043 if (mit != outFormats.cend() && mimeData->formats().contains(mimeType))
1044 formatetcs += setCf(mit.key());
1045 return formatetcs;
1046}
1047
1048bool QBuiltInMimes::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
1049{
1050 const auto mit = std::find(inFormats.cbegin(), inFormats.cend(), mimeType);
1051 return mit != inFormats.cend() && canGetData(mit.key(), pDataObj);
1052}
1053
1054QVariant QBuiltInMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QMetaType preferredType) const
1055{
1056 QVariant val;
1057 if (canConvertToMime(mimeType, pDataObj)) {
1058 QByteArray data = getData(inFormats.key(mimeType), pDataObj);
1059 if (!data.isEmpty()) {
1060 qCDebug(lcQpaMime) << __FUNCTION__;
1061 if (mimeType == u"text/html" && preferredType == QMetaType(QMetaType::QString)) {
1062 // text/html is in wide chars on windows (compatible with Mozilla)
1063 val = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData()));
1064 } else {
1065 val = data; // it should be enough to return the data and let QMimeData do the rest.
1066 }
1067 }
1068 }
1069 return val;
1070}
1071
1073{
1074 return inFormats.value(getCf(formatetc));
1075}
1076
1077
1079{
1080public:
1081
1083 // for converting from Qt
1084 bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
1085 bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override;
1086 QList<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
1087
1088 // for converting to Qt
1089 bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
1090 QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const override;
1091 QString mimeForFormat(const FORMATETC &formatetc) const override;
1092
1093private:
1094 mutable QMap<int, QString> formats;
1095 static QStringList ianaTypes;
1096 static QStringList excludeList;
1097};
1098
1099QStringList QLastResortMimes::ianaTypes;
1100QStringList QLastResortMimes::excludeList;
1101
1103{
1104 //MIME Media-Types
1105 if (ianaTypes.isEmpty()) {
1106 ianaTypes.append(u"application/"_s);
1107 ianaTypes.append(u"audio/"_s);
1108 ianaTypes.append(u"example/"_s);
1109 ianaTypes.append(u"image/"_s);
1110 ianaTypes.append(u"message/"_s);
1111 ianaTypes.append(u"model/"_s);
1112 ianaTypes.append(u"multipart/"_s);
1113 ianaTypes.append(u"text/"_s);
1114 ianaTypes.append(u"video/"_s);
1115 }
1116 //Types handled by other classes
1117 if (excludeList.isEmpty()) {
1118 excludeList.append(u"HTML Format"_s);
1119 excludeList.append(u"UniformResourceLocator"_s);
1120 excludeList.append(u"text/html"_s);
1121 excludeList.append(u"text/plain"_s);
1122 excludeList.append(u"text/uri-list"_s);
1123 excludeList.append(u"application/x-qt-image"_s);
1124 excludeList.append(u"application/x-color"_s);
1125 }
1126}
1127
1129{
1130 // really check
1131#if QT_CONFIG(draganddrop)
1132 return formatetc.tymed & TYMED_HGLOBAL
1133 && (formats.contains(formatetc.cfFormat)
1134 && QInternalMimeData::hasFormatHelper(formats.value(formatetc.cfFormat), mimeData));
1135#else
1137 Q_UNUSED(formatetc);
1138 return formatetc.tymed & TYMED_HGLOBAL
1139 && formats.contains(formatetc.cfFormat);
1140#endif // QT_CONFIG(draganddrop)
1141}
1142
1143bool QLastResortMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
1144{
1145#if QT_CONFIG(draganddrop)
1146 return canConvertFromMime(formatetc, mimeData)
1147 && setData(QInternalMimeData::renderDataHelper(formats.value(getCf(formatetc)), mimeData), pmedium);
1148#else
1150 Q_UNUSED(formatetc);
1151 Q_UNUSED(pmedium);
1152 return false;
1153#endif // QT_CONFIG(draganddrop)
1154}
1155
1156QList<FORMATETC> QLastResortMimes::formatsForMime(const QString &mimeType, const QMimeData * /*mimeData*/) const
1157{
1158 QList<FORMATETC> formatetcs;
1159 auto mit = std::find(formats.begin(), formats.end(), mimeType);
1160 // register any other available formats
1161 if (mit == formats.end() && !excludeList.contains(mimeType, Qt::CaseInsensitive))
1162 mit = formats.insert(registerMimeType(mimeType), mimeType);
1163 if (mit != formats.end())
1164 formatetcs += setCf(mit.key());
1165
1166 if (!formatetcs.isEmpty())
1167 qCDebug(lcQpaMime) << __FUNCTION__ << mimeType << formatetcs;
1168 return formatetcs;
1169}
1170static const char x_qt_windows_mime[] = "application/x-qt-windows-mime;value=\"";
1171
1173{
1175}
1176
1177static QString customMimeType(const QString &mimeType, int *lindex = nullptr)
1178{
1179 int len = sizeof(x_qt_windows_mime) - 1;
1180 int n = mimeType.lastIndexOf(u'\"') - len;
1181 QString ret = mimeType.mid(len, n);
1182
1183 const int beginPos = mimeType.indexOf(u";index=");
1184 if (beginPos > -1) {
1185 const int endPos = mimeType.indexOf(u';', beginPos + 1);
1186 const int indexStartPos = beginPos + 7;
1187 if (lindex)
1188 *lindex = QStringView{mimeType}.mid(indexStartPos, endPos == -1 ? endPos : endPos - indexStartPos).toInt();
1189 } else {
1190 if (lindex)
1191 *lindex = -1;
1192 }
1193 return ret;
1194}
1195
1196bool QLastResortMimes::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
1197{
1199 // MSDN documentation for QueryGetData says only -1 is supported, so ignore lindex here.
1200 QString clipFormat = customMimeType(mimeType);
1201 const UINT cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16()));
1202 return canGetData(int(cf), pDataObj);
1203 }
1204 // if it is not in there then register it and see if we can get it
1205 const auto mit = std::find(formats.cbegin(), formats.cend(), mimeType);
1206 const int cf = mit != formats.cend() ? mit.key() : registerMimeType(mimeType);
1207 return canGetData(cf, pDataObj);
1208}
1209
1210QVariant QLastResortMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QMetaType preferredType) const
1211{
1212 Q_UNUSED(preferredType);
1213 QVariant val;
1214 if (canConvertToMime(mimeType, pDataObj)) {
1217 int lindex;
1218 QString clipFormat = customMimeType(mimeType, &lindex);
1219 const UINT cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16()));
1220 data = getData(int(cf), pDataObj, lindex);
1221 } else {
1222 const auto mit = std::find(formats.cbegin(), formats.cend(), mimeType);
1223 const int cf = mit != formats.cend() ? mit.key() : registerMimeType(mimeType);
1224 data = getData(cf, pDataObj);
1225 }
1226 if (!data.isEmpty())
1227 val = data; // it should be enough to return the data and let QMimeData do the rest.
1228 }
1229 return val;
1230}
1231
1233{
1234 QString format = formats.value(getCf(formatetc));
1235 if (!format.isEmpty())
1236 return format;
1237
1238 const QString clipFormat = QWindowsMimeRegistry::clipboardFormatName(getCf(formatetc));
1239 if (!clipFormat.isEmpty()) {
1240#if QT_CONFIG(draganddrop)
1241 if (QInternalMimeData::canReadData(clipFormat))
1242 format = clipFormat;
1243 else if ((formatetc.cfFormat >= 0xC000)){
1244 //create the mime as custom. not registered.
1245 if (!excludeList.contains(clipFormat, Qt::CaseInsensitive)) {
1246 //check if this is a mime type
1247 bool ianaType = false;
1248 int sz = ianaTypes.size();
1249 for (int i = 0; i < sz; i++) {
1250 if (clipFormat.startsWith(ianaTypes[i], Qt::CaseInsensitive)) {
1251 ianaType = true;
1252 break;
1253 }
1254 }
1255 if (!ianaType)
1256 format = QLatin1StringView(x_qt_windows_mime) + clipFormat + u'"';
1257 else
1258 format = clipFormat;
1259 }
1260 }
1261#endif // QT_CONFIG(draganddrop)
1262 }
1263
1264 return format;
1265}
1266
1275
1277{
1278 qDeleteAll(m_mimes.begin(), m_mimes.begin() + m_internalMimeCount);
1279}
1280
1282{
1283 ensureInitialized();
1284 for (int i = m_mimes.size()-1; i >= 0; --i) {
1285 if (m_mimes.at(i)->canConvertToMime(mimeType, pDataObj))
1286 return m_mimes.at(i);
1287 }
1288 return nullptr;
1289}
1290
1292{
1293 qCDebug(lcQpaMime) << "QWindowsMimeConverter::allMimesForFormats()";
1294 ensureInitialized();
1296 LPENUMFORMATETC FAR fmtenum;
1297 HRESULT hr = pDataObj->EnumFormatEtc(DATADIR_GET, &fmtenum);
1298
1299 if (hr == NOERROR) {
1300 FORMATETC fmtetc;
1301 while (S_OK == fmtenum->Next(1, &fmtetc, nullptr)) {
1302 for (int i= m_mimes.size() - 1; i >= 0; --i) {
1303 QString format = m_mimes.at(i)->mimeForFormat(fmtetc);
1304 if (!format.isEmpty() && !formats.contains(format)) {
1305 formats += format;
1306 if (QWindowsContext::verbose > 1 && lcQpaMime().isDebugEnabled())
1307 qCDebug(lcQpaMime) << __FUNCTION__ << fmtetc << format;
1308 }
1309 }
1310 // as documented in MSDN to avoid possible memleak
1311 if (fmtetc.ptd)
1312 CoTaskMemFree(fmtetc.ptd);
1313 }
1314 fmtenum->Release();
1315 }
1316 qCDebug(lcQpaMime) << pDataObj << formats;
1317 return formats;
1318}
1319
1321{
1322 ensureInitialized();
1323 qCDebug(lcQpaMime) << __FUNCTION__ << formatetc;
1324 for (int i = m_mimes.size()-1; i >= 0; --i) {
1325 if (m_mimes.at(i)->canConvertFromMime(formatetc, mimeData))
1326 return m_mimes.at(i);
1327 }
1328 return nullptr;
1329}
1330
1332{
1333 ensureInitialized();
1334 QList<FORMATETC> formatics;
1335#if !QT_CONFIG(draganddrop)
1337#else
1338 formatics.reserve(20);
1340 for (int f = 0; f < formats.size(); ++f) {
1341 for (int i = m_mimes.size() - 1; i >= 0; --i)
1342 formatics += m_mimes.at(i)->formatsForMime(formats.at(f), mimeData);
1343 }
1344#endif // QT_CONFIG(draganddrop)
1345 return formatics;
1346}
1347
1348void QWindowsMimeRegistry::ensureInitialized() const
1349{
1350 if (m_internalMimeCount == 0) {
1351 m_internalMimeCount = -1; // prevent reentrancy when types register themselves
1352#ifndef QT_NO_IMAGEFORMAT_BMP
1354#endif //QT_NO_IMAGEFORMAT_BMP
1357 (void)new QWindowsMimeURI;
1359 (void)new QBuiltInMimes;
1360 m_internalMimeCount = m_mimes.size();
1361 Q_ASSERT(m_internalMimeCount > 0);
1362 }
1363}
1364
1366{
1367 wchar_t buf[256] = {0};
1368 return GetClipboardFormatName(UINT(cf), buf, 255)
1370}
1371
1373 IDataObject *pDataObj,
1374 QMetaType preferredType,
1375 QString *formatIn /* = 0 */) const
1376{
1377 for (const QString &format : mimeTypes) {
1378 if (const QWindowsMimeConverter *converter = converterToMime(format, pDataObj)) {
1379 if (converter->canConvertToMime(format, pDataObj)) {
1380 const QVariant dataV = converter->convertToMime(format, pDataObj, preferredType);
1381 if (dataV.isValid()) {
1382 qCDebug(lcQpaMime) << __FUNCTION__ << mimeTypes << "\nFormat: "
1383 << format << pDataObj << " returns " << dataV;
1384 if (formatIn)
1385 *formatIn = format;
1386 return dataV;
1387 }
1388 }
1389 }
1390 }
1391 qCDebug(lcQpaMime) << __FUNCTION__ << "fails" << mimeTypes << pDataObj << preferredType.id();
1392 return QVariant();
1393}
1394
1396{
1397 ensureInitialized();
1398 m_mimes.append(mime);
1399}
1400
1409{
1411 const UINT f = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (mimeType.utf16()));
1412 if (!f) {
1413 qErrnoWarning("QWindowsMimeRegistry::registerMimeType: Failed to register clipboard format "
1414 "for %s", qPrintable(mime));
1415 }
1416
1417 return int(f);
1418}
1419
\inmodule QtCore \reentrant
Definition qbuffer.h:16
QList< FORMATETC > formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override
Returns a QList of FORMATETC structures representing the different windows clipboard formats that can...
bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override
Returns true if the converter can convert to the mimeType from the available formats in pDataObj.
QString mimeForFormat(const FORMATETC &formatetc) const override
Returns the mime type that will be created form the format specified in formatetc,...
bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const override
Convert the mimeData to the format specified in formatetc.
QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const override
Returns a QVariant containing the converted data for mimeType from pDataObj.
bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override
Returns true if the converter can convert from the mimeData to the format specified in formatetc.
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
int toInt(bool *ok=nullptr, int base=10) const
Returns the byte array converted to an int using base base, which is ten by default.
char at(qsizetype i) const
Returns the byte at index position i in the byte array.
Definition qbytearray.h:600
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:107
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
void clear()
Clears the contents of the byte array and makes it null.
QByteArray mid(qsizetype index, qsizetype len=-1) const &
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
Definition qbytearray.h:409
QByteArray & replace(qsizetype index, qsizetype len, const char *s, qsizetype alen)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qbytearray.h:339
\inmodule QtCore
\inmodule QtCore\reentrant
Definition qdatastream.h:46
\inmodule QtCore
\inmodule QtCore
static QString toNativeSeparators(const QString &pathName)
Definition qdir.cpp:929
\inmodule QtCore \reentrant
Definition qiodevice.h:34
The QImageReader class provides a format independent interface for reading images from files or other...
bool canRead() const
Returns true if an image can be read for the device (i.e., the image format is supported,...
static QList< QByteArray > supportedImageFormats()
Returns the list of image formats supported by QImageReader.
QImage read()
Reads an image from the device.
The QImageWriter class provides a format independent interface for writing images to files or other d...
\inmodule QtGui
Definition qimage.h:37
@ Format_RGB32
Definition qimage.h:46
@ Format_ARGB32
Definition qimage.h:47
static bool hasFormatHelper(const QString &mimeType, const QMimeData *data)
static QByteArray renderDataHelper(const QString &mimeType, const QMimeData *data)
static bool canReadData(const QString &mimeType)
static QStringList formatsHelper(const QMimeData *data)
QString mimeForFormat(const FORMATETC &formatetc) const override
Returns the mime type that will be created form the format specified in formatetc,...
QList< FORMATETC > formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override
Returns a QList of FORMATETC structures representing the different windows clipboard formats that can...
bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override
Returns true if the converter can convert to the mimeType from the available formats in pDataObj.
QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const override
Returns a QVariant containing the converted data for mimeType from pDataObj.
bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const override
Convert the mimeData to the format specified in formatetc.
bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override
Returns true if the converter can convert from the mimeData to the format specified in formatetc.
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
iterator begin()
Definition qlist.h:625
void append(parameter_type t)
Definition qlist.h:458
iterator insert(const Key &key, const T &value)
Definition qmap.h:688
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:357
bool contains(const Key &key) const
Definition qmap.h:341
const_iterator cend() const
Definition qmap.h:605
const_iterator cbegin() const
Definition qmap.h:601
Key key(const T &value, const Key &defaultKey=Key()) const
Definition qmap.h:349
\inmodule QtCore
Definition qmetatype.h:341
int id(int=0) const
Definition qmetatype.h:475
\inmodule QtCore
Definition qmimedata.h:16
bool hasUrls() const
Returns true if the object can return a list of urls; otherwise returns false.
QVariant imageData() const
Returns a QVariant storing a QImage if the object can return an image; otherwise returns a null varia...
bool hasImage() const
Returns true if the object can return an image; otherwise returns false.
bool hasText() const
Returns true if the object can return plain text (MIME type text/plain); otherwise returns false.
QString html() const
Returns a string if the data stored in the object is HTML (MIME type text/html); otherwise returns an...
QList< QUrl > urls() const
Returns a list of URLs contained within the MIME data object.
virtual QStringList formats() const
Returns a list of formats supported by the object.
QString text() const
Returns a plain text (MIME type text/plain) representation of the data.
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5949
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
QByteArray toLocal8Bit() const &
Definition qstring.h:638
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
Definition qstring.h:1309
QByteArray toUtf8() const &
Definition qstring.h:634
const QChar * unicode() const
Returns a Unicode representation of the string.
Definition qstring.h:1230
qsizetype length() const noexcept
Returns the number of characters in this string.
Definition qstring.h:191
\inmodule QtCore
Definition qurl.h:94
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
Definition qurl.cpp:3368
bool isLocalFile() const
Definition qurl.cpp:3445
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2831
QString toLocalFile() const
Returns the path of this URL formatted as a local file path.
Definition qurl.cpp:3425
\inmodule QtCore
Definition qvariant.h:65
The QWindowsMimeConverter class maps open-standard MIME to Window Clipboard formats.
virtual QList< FORMATETC > formatsForMime(const QString &mimeType, const QMimeData *mimeData) const =0
Returns a QList of FORMATETC structures representing the different windows clipboard formats that can...
virtual bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const =0
Returns true if the converter can convert from the mimeData to the format specified in formatetc.
static int registerMimeType(const QString &mimeType)
Registers the MIME type mimeType, and returns an ID number identifying the format on Windows.
virtual QString mimeForFormat(const FORMATETC &formatetc) const =0
Returns the mime type that will be created form the format specified in formatetc,...
virtual bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const =0
Returns true if the converter can convert to the mimeType from the available formats in pDataObj.
bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override
Returns true if the converter can convert from the mimeData to the format specified in formatetc.
bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const override
Convert the mimeData to the format specified in formatetc.
QString mimeForFormat(const FORMATETC &formatetc) const override
Returns the mime type that will be created form the format specified in formatetc,...
bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override
Returns true if the converter can convert to the mimeType from the available formats in pDataObj.
QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const override
Returns a QVariant containing the converted data for mimeType from pDataObj.
QList< FORMATETC > formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override
Returns a QList of FORMATETC structures representing the different windows clipboard formats that can...
bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override
Returns true if the converter can convert from the mimeData to the format specified in formatetc.
QString mimeForFormat(const FORMATETC &formatetc) const override
Returns the mime type that will be created form the format specified in formatetc,...
QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QMetaType preferredType) const override
Returns a QVariant containing the converted data for mimeType from pDataObj.
bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const override
Convert the mimeData to the format specified in formatetc.
bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override
Returns true if the converter can convert to the mimeType from the available formats in pDataObj.
QList< FORMATETC > formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override
Returns a QList of FORMATETC structures representing the different windows clipboard formats that can...
static int registerMimeType(const QString &mime)
Registers the MIME type mime, and returns an ID number identifying the format on Windows.
static QString clipboardFormatName(int cf)
QVariant convertToMime(const QStringList &mimeTypes, IDataObject *pDataObj, QMetaType preferredType, QString *format=nullptr) const
QWindowsMimeConverter * converterFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
void registerMime(QWindowsMimeConverter *mime)
QStringList allMimesForFormats(IDataObject *pDataObj) const
QList< FORMATETC > allFormatsForMime(const QMimeData *mimeData) const
QWindowsMimeConverter QWindowsMimeConverter
QWindowsMimeConverter * converterToMime(const QString &mimeType, IDataObject *pDataObj) const
bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override
Returns true if the converter can convert to the mimeType from the available formats in pDataObj.
bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override
Returns true if the converter can convert from the mimeData to the format specified in formatetc.
QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QMetaType preferredType) const override
bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const override
Convert the mimeData to the format specified in formatetc.
QList< FORMATETC > formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override
Returns a QList of FORMATETC structures representing the different windows clipboard formats that can...
QString mimeForFormat(const FORMATETC &formatetc) const override
Returns the mime type that will be created form the format specified in formatetc,...
QList< FORMATETC > formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override
Returns a QList of FORMATETC structures representing the different windows clipboard formats that can...
QString mimeForFormat(const FORMATETC &formatetc) const override
Returns the mime type that will be created form the format specified in formatetc,...
bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override
Returns true if the converter can convert to the mimeType from the available formats in pDataObj.
QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QMetaType preferredType) const override
bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override
Returns true if the converter can convert from the mimeData to the format specified in formatetc.
bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const override
Convert the mimeData to the format specified in formatetc.
QString str
[2]
qDeleteAll(list.begin(), list.end())
void qErrnoWarning(const char *msg,...)
EGLint EGLint * formats
Combined button and popup list for selecting options.
@ CaseInsensitive
Definition image.cpp:4
size_t qstrlen(const char *str)
constexpr QStaticByteArrayMatcher< N > qMakeStaticByteArrayMatcher(const char(&pattern)[N]) noexcept
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
const char * mimeType
#define qWarning
Definition qlogging.h:166
#define qCDebug(category,...)
return ret
GLboolean GLboolean GLboolean b
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLenum GLuint buffer
GLenum GLuint GLenum GLsizei const GLchar * buf
GLuint start
GLfloat n
GLint GLsizei GLsizei GLenum format
GLint y
GLdouble s
[6]
Definition qopenglext.h:235
GLenum func
Definition qopenglext.h:663
GLuint res
const GLubyte * c
GLuint GLfloat * val
GLint void * img
Definition qopenglext.h:233
const GLfloat * tc
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLenum GLsizei len
GLfloat GLfloat GLfloat alpha
Definition qopenglext.h:418
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
Definition qrgb.h:13
constexpr int qRed(QRgb rgb)
Definition qrgb.h:18
constexpr int qGreen(QRgb rgb)
Definition qrgb.h:21
constexpr int qBlue(QRgb rgb)
Definition qrgb.h:24
constexpr int qAlpha(QRgb rgb)
Definition qrgb.h:27
#define qPrintable(string)
Definition qstring.h:1531
#define Q_UNUSED(x)
unsigned char uchar
Definition qtypes.h:32
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned short ushort
Definition qtypes.h:33
static int toInt(const QChar &qc, int R)
long HRESULT
tagSTGMEDIUM STGMEDIUM
tagFORMATETC FORMATETC
#define BMP_LCS_GM_IMAGES
static QByteArray msgConversionError(const char *func, const char *format)
static bool canGetData(int cf, IDataObject *pDataObj)
static FORMATETC setCf(int cf)
static bool isCustomMimeType(const QString &mimeType)
static QByteArray writeDib(const QImage &img)
static QByteArray getData(int cf, IDataObject *pDataObj, int lindex=-1)
static QString customMimeType(const QString &mimeType, int *lindex=nullptr)
static bool readDib(QBuffer &buffer, QImage &img)
QDebug operator<<(QDebug d, const FORMATETC &tc)
static const char dibFormatC[]
static const char x_qt_windows_mime[]
static bool qt_write_dibv5(QDataStream &s, QImage image)
static int getCf(const FORMATETC &formatetc)
static bool setData(const QByteArray &data, STGMEDIUM *pmedium)
#define BMP_LCS_sRGB
QByteArray ba
[0]
QTextStream out(stdout)
[7]
QUrl url("example.com")
[constructor-url-reference]
application x qt windows mime
[2]
QMimeData * mimeData
QStringList fileNames
[4]
QStringList files
[8]