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>
22using namespace Qt::StringLiterals;
25
26
27
28#define BMP_LCS_sRGB 0x73524742
29#define BMP_LCS_GM_IMAGES 0x00000004L
70 QByteArray msg = func;
71 msg +=
": Unable to convert DIB image. The image converter plugin for '";
73 msg +=
"' is not available. Available formats: ";
74 const auto &formats = QImageReader::supportedImageFormats();
75 for (
const QByteArray &af : formats) {
82static inline bool readDib(QBuffer &buffer, QImage &img)
85 if (!reader.canRead()) {
86 qWarning(
"%s", msgConversionError(
__FUNCTION__, dibFormatC).constData());
97 buffer.open(QIODevice::ReadWrite);
99 if (!writer.canWrite()) {
100 qWarning(
"%s", msgConversionError(
__FUNCTION__, dibFormatC).constData());
103 if (!writer.write(img))
110 QIODevice* d = s.device();
111 if (!d->isWritable())
115 qsizetype bpl_bmp = qsizetype(image.width()) * 4;
116 qsizetype size = bpl_bmp * image.height();
117 if (qsizetype(DWORD(size)) != size)
121 ZeroMemory(&bi,
sizeof(bi));
123 bi.bV5Width = image.width();
124 bi.bV5Height = image.height();
127 bi.bV5Compression = BI_BITFIELDS;
128 bi.bV5SizeImage = DWORD(bpl_bmp * image.height());
129 bi.bV5XPelsPerMeter = 0;
130 bi.bV5YPelsPerMeter = 0;
132 bi.bV5ClrImportant = 0;
133 bi.bV5BlueMask = 0x000000ff;
134 bi.bV5GreenMask = 0x0000ff00;
135 bi.bV5RedMask = 0x00ff0000;
136 bi.bV5AlphaMask = 0xff000000;
140 d->write(
reinterpret_cast<
const char*>(&bi), bi.bV5Size);
141 if (s.status() != QDataStream::Ok)
144 d->write(
reinterpret_cast<
const char *>(&bi.bV5RedMask),
sizeof(bi.bV5RedMask));
145 if (s.status() != QDataStream::Ok)
148 d->write(
reinterpret_cast<
const char *>(&bi.bV5GreenMask),
sizeof(bi.bV5GreenMask));
149 if (s.status() != QDataStream::Ok)
152 d->write(
reinterpret_cast<
const char *>(&bi.bV5BlueMask),
sizeof(bi.bV5BlueMask));
153 if (s.status() != QDataStream::Ok)
156 if (image.format() != QImage::Format_ARGB32)
157 image = std::move(image).convertToFormat(QImage::Format_ARGB32);
159 auto *buf =
new uchar[bpl_bmp];
161 memset(buf, 0, size_t(bpl_bmp));
162 for (
int y=image.height()-1; y>=0; y--) {
164 const QRgb *p =
reinterpret_cast<
const QRgb *>(image.constScanLine(y));
165 const QRgb *end = p + image.width();
168 int alpha = qAlpha(*p);
170 *b++ = uchar(qBlue(*p));
171 *b++ = uchar(qGreen(*p));
172 *b++ = uchar(qRed(*p));
182 d->write(
reinterpret_cast<
const char *>(buf), bpl_bmp);
183 if (s.status() != QDataStream::Ok) {
194static int getCf(
const FORMATETC &formatetc)
196 return formatetc.cfFormat;
202 formatetc.cfFormat = CLIPFORMAT(cf);
203 formatetc.dwAspect = DVASPECT_CONTENT;
204 formatetc.lindex = -1;
205 formatetc.ptd =
nullptr;
206 formatetc.tymed = TYMED_HGLOBAL;
210static bool setData(
const QByteArray &data, STGMEDIUM *pmedium)
212 HGLOBAL hData = GlobalAlloc(0, SIZE_T(data.size()));
216 void *out = GlobalLock(hData);
217 memcpy(out, data.data(), size_t(data.size()));
219 pmedium->tymed = TYMED_HGLOBAL;
220 pmedium->hGlobal = hData;
221 pmedium->pUnkForRelease =
nullptr;
228 FORMATETC formatetc = setCf(cf);
229 formatetc.lindex = lindex;
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)));
235 GlobalUnlock(s.hGlobal);
236 ReleaseStgMedium(&s);
239 formatetc.tymed = TYMED_ISTREAM;
240 if (pDataObj->GetData(&formatetc, &s) == S_OK) {
242 ULONG actualRead = 0;
243 LARGE_INTEGER pos = {{0, 0}};
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));
251 if (actualRead !=
sizeof(szBuffer))
255 ReleaseStgMedium(&s);
263 FORMATETC formatetc = setCf(cf);
264 if (pDataObj->QueryGetData(&formatetc) != S_OK){
265 formatetc.tymed = TYMED_ISTREAM;
266 return pDataObj->QueryGetData(&formatetc) == S_OK;
271#ifndef QT_NO_DEBUG_STREAM
272QDebug operator<<(QDebug d,
const FORMATETC &tc)
274 QDebugStateSaver saver(d);
276 d <<
"FORMATETC(cfFormat=" << tc.cfFormat <<
' ';
277 switch (tc.cfFormat) {
297 d <<
"CF_UNICODETEXT";
300 d <<
"CF_ENHMETAFILE";
303 d << QWindowsMimeRegistry::clipboardFormatName(tc.cfFormat);
306 d <<
", dwAspect=" << tc.dwAspect <<
", lindex=" << tc.lindex
307 <<
", tymed=" << tc.tymed <<
", ptd=" << tc.ptd <<
')';
311QDebug operator<<(QDebug d, IDataObject *dataObj)
313 QDebugStateSaver saver(d);
318 IEnumFORMATETC *enumFormatEtc;
319 if (SUCCEEDED(dataObj->EnumFormatEtc(DATADIR_GET, &enumFormatEtc)) && enumFormatEtc) {
320 FORMATETC formatEtc[1];
322 if (SUCCEEDED(enumFormatEtc->Reset())) {
323 while (SUCCEEDED(enumFormatEtc->Next(1, formatEtc, &fetched)) && fetched)
324 d << formatEtc[0] <<
',';
325 enumFormatEtc->Release();
343 bool convertFromMime(
const FORMATETC &formatetc,
const QMimeData *mimeData, STGMEDIUM *pmedium)
const override;
349 int cf = getCf(formatetc);
350 return (cf == CF_UNICODETEXT || (cf == CF_TEXT && GetACP() != CP_UTF8)) && mimeData->hasText();
354
355
356
357
360 if (canConvertFromMime(formatetc, mimeData)) {
362 int cf = getCf(formatetc);
364 data = mimeData->text().toLocal8Bit();
366 int maxsize=data.size()+data.size()/40+3;
367 QByteArray r(maxsize,
'\0');
369 const char* d = data.data();
370 const int s = data.size();
373 for (
int i=0; i<s; i++) {
385 if (j+3 >= maxsize) {
386 maxsize += maxsize/4;
392 return setData(r, pmedium);
394 if (cf == CF_UNICODETEXT) {
395 QString str = mimeData->text();
396 const QChar *u = str.unicode();
398 const int s = str.length();
399 int maxsize = s + s/40 + 3;
403 for (
int i=0; i < s; ++i) {
407 if (*u == u'\n' && !cr)
412 if (ri+3 >= maxsize) {
413 maxsize += maxsize/4;
419 const int byteLength = res.length() *
int(
sizeof(ushort));
420 QByteArray r(byteLength + 2,
'\0');
421 memcpy(r.data(), res.unicode(), size_t(byteLength));
424 return setData(r, pmedium);
432 return mimeType.startsWith(u"text/plain")
433 && (canGetData(CF_UNICODETEXT, pDataObj)
434 || canGetData(CF_TEXT, pDataObj));
439 int cf = getCf(formatetc);
440 if (cf == CF_UNICODETEXT || cf == CF_TEXT)
441 return u"text/plain"_s;
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);
461 if (canConvertToMime(mime, pDataObj)) {
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);
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');
475 for (
unsigned i = 0; i < s; ++i) {
481 str = QString::fromLocal8Bit(r);
484 if (preferredType.id() == QMetaType::QString)
487 ret =
std::move(str).toUtf8();
489 qCDebug(lcQpaMime) <<
__FUNCTION__ << ret;
501 bool convertFromMime(
const FORMATETC &formatetc,
const QMimeData *mimeData, STGMEDIUM *pmedium)
const override;
510 CF_INETURL_W = registerMimeType(u"UniformResourceLocatorW"_s);
511 CF_INETURL = registerMimeType(u"UniformResourceLocator"_s);
516 if (mimeData->hasUrls() && getCf(formatetc) == CF_HDROP) {
517 const auto urls = mimeData->urls();
518 for (
const QUrl &url : urls) {
519 if (url.isLocalFile())
523 return (getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL) && mimeData->hasUrls();
528 if (canConvertFromMime(formatetc, mimeData)) {
529 if (getCf(formatetc) == CF_HDROP) {
530 const auto &urls = mimeData->urls();
531 QStringList fileNames;
532 size_t size =
sizeof(DROPFILES) + 2;
533 for (
const QUrl &url : urls) {
534 const QString fn = QDir::toNativeSeparators(url.toLocalFile());
536 size +=
sizeof(ushort) * size_t(fn.length() + 1);
537 fileNames.append(fn);
541 QByteArray result(
int(size),
'\0');
542 auto* d =
reinterpret_cast<DROPFILES *>(result.data());
543 d->pFiles =
sizeof(DROPFILES);
544 GetCursorPos(&d->pt);
546 char *files = (
reinterpret_cast<
char*>(d)) + d->pFiles;
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));
558 return setData(result, pmedium);
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)));
570 return setData(result, pmedium);
572 if (getCf(formatetc) == CF_INETURL) {
573 const auto urls = mimeData->urls();
576 result = urls.at(0).toString().toLocal8Bit();
577 return setData(result, pmedium);
586 return mimeType == u"text/uri-list"
587 && (canGetData(CF_HDROP, pDataObj) || canGetData(CF_INETURL_W, pDataObj) || canGetData(CF_INETURL, pDataObj));
593 if (getCf(formatetc) == CF_HDROP || getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL)
594 format = u"text/uri-list"_s;
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);
614 if (mimeType == u"text/uri-list") {
615 if (canGetData(CF_HDROP, pDataObj)) {
616 QList<QVariant> urls;
618 QByteArray data = getData(CF_HDROP, pDataObj);
622 const auto *hdrop =
reinterpret_cast<
const DROPFILES *>(data.constData());
624 const auto *filesw =
reinterpret_cast<
const wchar_t *>(data.constData() + hdrop->pFiles);
627 QString fileurl = QString::fromWCharArray(filesw + i);
628 urls += QUrl::fromLocalFile(fileurl);
629 i += fileurl.length()+1;
632 const char* files =
reinterpret_cast<
const char *>(data.constData() + hdrop->pFiles);
635 urls += QUrl::fromLocalFile(QString::fromLocal8Bit(files+i));
636 i +=
int(strlen(files+i))+1;
640 if (preferredType.id() == QMetaType::QUrl && urls.size() == 1)
644 }
else if (canGetData(CF_INETURL_W, pDataObj)) {
645 QByteArray data = getData(CF_INETURL_W, pDataObj);
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);
653 return QUrl(QString::fromLocal8Bit(data.constData()));
666 bool convertFromMime(
const FORMATETC &formatetc,
const QMimeData *mimeData, STGMEDIUM * pmedium)
const override;
680 CF_HTML = registerMimeType(u"HTML Format"_s);
685 QList<FORMATETC> formatetcs;
686 if (mimeType == u"text/html" && (!mimeData->html().isEmpty()))
687 formatetcs += setCf(CF_HTML);
693 if (getCf(formatetc) == CF_HTML)
694 return u"text/html"_s;
700 return mimeType == u"text/html" && canGetData(CF_HTML, pDataObj);
706 return getCf(formatetc) == CF_HTML && (!mimeData->html().isEmpty());
710
711
712
713
714
715
716
717
718
719
720
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);
734 int startOffset = start + 10;
736 while (html.at(i) !=
'\r' && html.at(i) !=
'\n')
738 QByteArray bytecount = html.mid(startOffset, i - startOffset);
739 start = bytecount.toInt();
743 int endOffset = end + 8;
745 while (html.at(i) !=
'\r' && html.at(i) !=
'\n')
747 QByteArray bytecount = html.mid(endOffset , i - endOffset);
748 end = bytecount.toInt();
751 if (end > start && start > 0) {
752 html = html.mid(start, end - start);
753 html.replace(
'\r',
"");
754 result = QString::fromUtf8(html);
762 if (canConvertFromMime(formatetc, mimeData)) {
763 QByteArray data = mimeData->html().toUtf8();
766 "StartHTML:0000000107\r\n"
767 "EndHTML:0000000000\r\n"
768 "StartFragment:0000000000\r\n"
769 "EndFragment:0000000000\r\n\r\n";
771 static constexpr auto startFragmentMatcher = qMakeStaticByteArrayMatcher(
"<!--StartFragment-->");
772 static constexpr auto endFragmentMatcher = qMakeStaticByteArrayMatcher(
"<!--EndFragment-->");
774 if (startFragmentMatcher.indexIn(data) == -1)
775 result +=
"<!--StartFragment-->";
777 if (endFragmentMatcher.indexIn(data) == -1)
778 result +=
"<!--EndFragment-->";
781 QByteArray pos = QByteArray::number(result.size());
782 memcpy(
reinterpret_cast<
char *>(result.data() + 53 - pos.length()), pos.constData(), size_t(pos.length()));
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()));
790 return setData(result, pmedium);
796#ifndef QT_NO_IMAGEFORMAT_BMP
803 bool convertFromMime(
const FORMATETC &formatetc,
const QMimeData *mimeData, STGMEDIUM * pmedium)
const override;
811 bool hasOriginalDIBV5(IDataObject *pDataObj)
const;
817 CF_PNG = RegisterClipboardFormat(L"PNG");
822 QList<FORMATETC> formatetcs;
823 if (mimeData->hasImage() && mimeType == u"application/x-qt-image") {
825 auto image = qvariant_cast<QImage>(mimeData->imageData());
826 if (!image.isNull() && image.hasAlphaChannel())
827 formatetcs += setCf(CF_DIBV5);
828 formatetcs += setCf(CF_DIB);
830 if (!formatetcs.isEmpty())
831 qCDebug(lcQpaMime) <<
__FUNCTION__ << mimeType << formatetcs;
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;
845 return mimeType == u"application/x-qt-image"
846 && (canGetData(CF_DIB, pDataObj) || canGetData(CF_PNG, pDataObj));
851 int cf = getCf(formatetc);
852 if (!mimeData->hasImage())
854 const QImage image = qvariant_cast<QImage>(mimeData->imageData());
859 return cf == CF_DIBV5 || cf == CF_DIB
860 || (cf ==
int(CF_PNG) && image.hasAlphaChannel());
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());
872 if (img.format() > QImage::Format_ARGB32)
873 img = std::move(img).convertToFormat(QImage::Format_RGB32);
874 const QByteArray ba = writeDib(img);
876 return setData(ba, pmedium);
877 }
else if (cf ==
int(CF_PNG)) {
879 const bool written = buffer.open(QIODevice::WriteOnly) && img.save(&buffer,
"PNG");
882 return setData(ba, pmedium);
884 QDataStream s(&ba, QIODevice::WriteOnly);
885 s.setByteOrder(QDataStream::LittleEndian);
886 if (qt_write_dibv5(s, std::move(img)))
887 return setData(ba, pmedium);
895 bool isSynthesized =
true;
896 IEnumFORMATETC *pEnum =
nullptr;
897 HRESULT res = pDataObj->EnumFormatEtc(1, &pEnum);
898 if (res == S_OK && pEnum) {
900 while ((res = pEnum->Next(1, &fc,
nullptr)) == S_OK) {
902 CoTaskMemFree(fc.ptd);
903 if (fc.cfFormat == CF_DIB)
905 if (fc.cfFormat == CF_DIBV5) {
906 isSynthesized =
false;
912 return !isSynthesized;
917 Q_UNUSED(preferredType);
919 if (mimeType != u"application/x-qt-image")
923 const bool canGetDibV5 = canGetData(CF_DIBV5, pDataObj);
924 const bool hasOrigDibV5 = canGetDibV5 ? hasOriginalDIBV5(pDataObj) :
false;
925 qCDebug(lcQpaMime) <<
"canGetDibV5:" << canGetDibV5 <<
"hasOrigDibV5:" << hasOrigDibV5;
927 if (!hasOrigDibV5 && canGetData(CF_PNG, pDataObj)) {
928 qCDebug(lcQpaMime) <<
"Decoding PNG";
930 QByteArray data = getData(CF_PNG, pDataObj);
931 if (img.loadFromData(data,
"PNG")) {
936 if (canGetDibV5 || canGetData(CF_DIB, pDataObj)) {
937 qCDebug(lcQpaMime) <<
"Decoding DIB";
939 QByteArray data = getData(canGetDibV5 ? CF_DIBV5 : CF_DIB, pDataObj);
940 QBuffer buffer(&data);
941 if (readDib(buffer, img))
956 bool convertFromMime(
const FORMATETC &formatetc,
const QMimeData *mimeData, STGMEDIUM * pmedium)
const override;
965 QMap<
int, QString> outFormats;
966 QMap<
int, QString> inFormats;
972 outFormats.insert(registerMimeType(u"application/x-color"_s), u"application/x-color"_s);
973 inFormats.insert(registerMimeType(u"application/x-color"_s), u"application/x-color"_s);
979 return formatetc.tymed & TYMED_HGLOBAL
980 && outFormats.contains(formatetc.cfFormat)
981 && mimeData->formats().contains(outFormats.value(formatetc.cfFormat));
986 if (canConvertFromMime(formatetc, mimeData)) {
988 if (outFormats.value(getCf(formatetc)) == u"text/html") {
990 QString html = mimeData->html();
992 const QChar *u = html.unicode();
994 const int s = html.length();
995 int maxsize = s + s/40 + 3;
999 for (
int i=0; i < s; ++i) {
1003 if (*u == u'\n' && !cr)
1008 if (ri+3 >= maxsize) {
1009 maxsize += maxsize/4;
1010 res.resize(maxsize);
1015 const int byteLength = res.length() *
int(
sizeof(ushort));
1016 QByteArray r(byteLength + 2,
'\0');
1017 memcpy(r.data(), res.unicode(), size_t(byteLength));
1019 r[byteLength+1] = 0;
1022#if QT_CONFIG(draganddrop)
1023 data = QInternalMimeData::renderDataHelper(outFormats.value(getCf(formatetc)), mimeData);
1026 return setData(data, pmedium);
1033 QList<FORMATETC> formatetcs;
1034 const auto mit = std::find(outFormats.cbegin(), outFormats.cend(), mimeType);
1035 if (mit != outFormats.cend() && mimeData->formats().contains(mimeType))
1036 formatetcs += setCf(mit.key());
1042 const auto mit = std::find(inFormats.cbegin(), inFormats.cend(), mimeType);
1043 return mit != inFormats.cend() && canGetData(mit.key(), pDataObj);
1049 if (canConvertToMime(mimeType, pDataObj)) {
1050 QByteArray data = getData(inFormats.key(mimeType), pDataObj);
1051 if (!data.isEmpty()) {
1052 qCDebug(lcQpaMime) <<
__FUNCTION__;
1053 if (mimeType == u"text/html" && preferredType == QMetaType(QMetaType::QString)) {
1055 val = QString::fromWCharArray(
reinterpret_cast<
const wchar_t *>(data.constData()));
1066 return inFormats.value(getCf(formatetc));
1077 bool convertFromMime(
const FORMATETC &formatetc,
const QMimeData *mimeData, STGMEDIUM * pmedium)
const override;
1086 mutable QMap<
int, QString> formats;
1087 static QStringList ianaTypes;
1088 static QStringList excludeList;
1097 if (ianaTypes.isEmpty()) {
1098 ianaTypes.append(u"application/"_s);
1099 ianaTypes.append(u"audio/"_s);
1100 ianaTypes.append(u"example/"_s);
1101 ianaTypes.append(u"image/"_s);
1102 ianaTypes.append(u"message/"_s);
1103 ianaTypes.append(u"model/"_s);
1104 ianaTypes.append(u"multipart/"_s);
1105 ianaTypes.append(u"text/"_s);
1106 ianaTypes.append(u"video/"_s);
1109 if (excludeList.isEmpty()) {
1110 excludeList.append(u"HTML Format"_s);
1111 excludeList.append(u"UniformResourceLocator"_s);
1112 excludeList.append(u"text/html"_s);
1113 excludeList.append(u"text/plain"_s);
1114 excludeList.append(u"text/uri-list"_s);
1115 excludeList.append(u"application/x-qt-image"_s);
1116 excludeList.append(u"application/x-color"_s);
1123#if QT_CONFIG(draganddrop)
1124 return formatetc.tymed & TYMED_HGLOBAL
1125 && (formats.contains(formatetc.cfFormat)
1126 && QInternalMimeData::hasFormatHelper(formats.value(formatetc.cfFormat), mimeData));
1129 Q_UNUSED(formatetc);
1130 return formatetc.tymed & TYMED_HGLOBAL
1131 && formats.contains(formatetc.cfFormat);
1137#if QT_CONFIG(draganddrop)
1138 return canConvertFromMime(formatetc, mimeData)
1139 && setData(QInternalMimeData::renderDataHelper(formats.value(getCf(formatetc)), mimeData), pmedium);
1142 Q_UNUSED(formatetc);
1150 QList<FORMATETC> formatetcs;
1151 auto mit = std::find(formats.begin(), formats.end(), mimeType);
1153 if (mit == formats.end() && !excludeList.contains(mimeType, Qt::CaseInsensitive))
1154 mit = formats.insert(registerMimeType(mimeType), mimeType);
1155 if (mit != formats.end())
1156 formatetcs += setCf(mit.key());
1158 if (!formatetcs.isEmpty())
1159 qCDebug(lcQpaMime) <<
__FUNCTION__ << mimeType << formatetcs;
1166 return mimeType.startsWith(QLatin1StringView(x_qt_windows_mime), Qt::CaseInsensitive);
1172 int n = mimeType.lastIndexOf(u'\"') - len;
1173 QString ret = mimeType.mid(len, n);
1175 const int beginPos = mimeType.indexOf(u";index=");
1176 if (beginPos > -1) {
1177 const int endPos = mimeType.indexOf(u';', beginPos + 1);
1178 const int indexStartPos = beginPos + 7;
1180 *lindex = QStringView{mimeType}.mid(indexStartPos, endPos == -1 ? endPos : endPos - indexStartPos).toInt();
1190 if (isCustomMimeType(mimeType)) {
1192 QString clipFormat = customMimeType(mimeType);
1193 const UINT cf = RegisterClipboardFormat(
reinterpret_cast<
const wchar_t *> (clipFormat.utf16()));
1194 return canGetData(
int(cf), pDataObj);
1197 const auto mit = std::find(formats.cbegin(), formats.cend(), mimeType);
1198 const int cf = mit != formats.cend() ? mit.key() : registerMimeType(mimeType);
1199 return canGetData(cf, pDataObj);
1204 Q_UNUSED(preferredType);
1206 if (canConvertToMime(mimeType, pDataObj)) {
1208 if (isCustomMimeType(mimeType)) {
1210 QString clipFormat = customMimeType(mimeType, &lindex);
1211 const UINT cf = RegisterClipboardFormat(
reinterpret_cast<
const wchar_t *> (clipFormat.utf16()));
1212 data = getData(
int(cf), pDataObj, lindex);
1214 const auto mit = std::find(formats.cbegin(), formats.cend(), mimeType);
1215 const int cf = mit != formats.cend() ? mit.key() : registerMimeType(mimeType);
1216 data = getData(cf, pDataObj);
1218 if (!data.isEmpty())
1226 QString format = formats.value(getCf(formatetc));
1227 if (!format.isEmpty())
1230 const QString clipFormat = QWindowsMimeRegistry::clipboardFormatName(getCf(formatetc));
1231 if (!clipFormat.isEmpty()) {
1232#if QT_CONFIG(draganddrop)
1233 if (QInternalMimeData::canReadData(clipFormat))
1234 format = clipFormat;
1235 else if ((formatetc.cfFormat >= 0xC000)){
1237 if (!excludeList.contains(clipFormat, Qt::CaseInsensitive)) {
1239 bool ianaType =
false;
1240 int sz = ianaTypes.size();
1241 for (
int i = 0; i < sz; i++) {
1242 if (clipFormat.startsWith(ianaTypes[i], Qt::CaseInsensitive)) {
1248 format = QLatin1StringView(x_qt_windows_mime) + clipFormat + u'"';
1250 format = clipFormat;
1260
1261
1262
1263
1264
1270 qDeleteAll(m_mimes.begin(), m_mimes.begin() + m_internalMimeCount);
1275 ensureInitialized();
1276 for (
int i = m_mimes.size()-1; i >= 0; --i) {
1277 if (m_mimes.at(i)->canConvertToMime(mimeType, pDataObj))
1278 return m_mimes.at(i);
1285 qCDebug(lcQpaMime) <<
"QWindowsMimeConverter::allMimesForFormats()";
1286 ensureInitialized();
1287 QStringList formats;
1288 LPENUMFORMATETC FAR fmtenum;
1289 HRESULT hr = pDataObj->EnumFormatEtc(DATADIR_GET, &fmtenum);
1291 if (hr == NOERROR) {
1293 while (S_OK == fmtenum->Next(1, &fmtetc,
nullptr)) {
1294 for (
int i= m_mimes.size() - 1; i >= 0; --i) {
1295 QString format = m_mimes.at(i)->mimeForFormat(fmtetc);
1296 if (!format.isEmpty() && !formats.contains(format)) {
1298 if (QWindowsContext::verbose > 1 && lcQpaMime().isDebugEnabled())
1299 qCDebug(lcQpaMime) <<
__FUNCTION__ << fmtetc << format;
1304 CoTaskMemFree(fmtetc.ptd);
1308 qCDebug(lcQpaMime) << pDataObj << formats;
1314 ensureInitialized();
1315 qCDebug(lcQpaMime) <<
__FUNCTION__ << formatetc;
1316 for (
int i = m_mimes.size()-1; i >= 0; --i) {
1317 if (m_mimes.at(i)->canConvertFromMime(formatetc, mimeData))
1318 return m_mimes.at(i);
1325 ensureInitialized();
1326 QList<FORMATETC> formatics;
1327#if !QT_CONFIG(draganddrop)
1330 formatics.reserve(20);
1331 const QStringList formats = QInternalMimeData::formatsHelper(mimeData);
1332 for (
int f = 0; f < formats.size(); ++f) {
1333 for (
int i = m_mimes.size() - 1; i >= 0; --i)
1334 formatics += m_mimes.at(i)->formatsForMime(formats.at(f), mimeData);
1342 if (m_internalMimeCount == 0) {
1343 m_internalMimeCount = -1;
1344#ifndef QT_NO_IMAGEFORMAT_BMP
1352 m_internalMimeCount = m_mimes.size();
1353 Q_ASSERT(m_internalMimeCount > 0);
1359 wchar_t buf[256] = {0};
1360 return GetClipboardFormatName(UINT(cf), buf, 255)
1361 ? QString::fromWCharArray(buf) : QString();
1365 IDataObject *pDataObj,
1366 QMetaType preferredType,
1367 QString *formatIn )
const
1369 for (
const QString &format : mimeTypes) {
1370 if (
const QWindowsMimeConverter *converter = converterToMime(format, pDataObj)) {
1371 if (converter->canConvertToMime(format, pDataObj)) {
1372 const QVariant dataV = converter->convertToMime(format, pDataObj, preferredType);
1373 if (dataV.isValid()) {
1374 qCDebug(lcQpaMime) <<
__FUNCTION__ << mimeTypes <<
"\nFormat: "
1375 << format << pDataObj <<
" returns " << dataV;
1383 qCDebug(lcQpaMime) <<
__FUNCTION__ <<
"fails" << mimeTypes << pDataObj << preferredType.id();
1389 ensureInitialized();
1390 m_mimes.append(mime);
1394
1395
1396
1397
1398
1399
1402 const QString mimeType = isCustomMimeType(mime) ? customMimeType(mime) : mime;
1403 const UINT f = RegisterClipboardFormat(
reinterpret_cast<
const wchar_t *> (mimeType.utf16()));
1405 qErrnoWarning(
"QWindowsMimeRegistry::registerMimeType: Failed to register clipboard format "
1406 "for %s", qPrintable(mime));
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.
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.
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...
Manages the list of QWindowsMimeConverter instances.
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 * 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.
#define BMP_LCS_GM_IMAGES
static QByteArray msgConversionError(const char *func, const char *format)
static const char x_qt_windows_mime[]
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)
static bool qt_write_dibv5(QDataStream &s, QImage image)
static int getCf(const FORMATETC &formatetc)
static const char dibFormatC[]
static bool setData(const QByteArray &data, STGMEDIUM *pmedium)