5#include "ClipboardMimeData.h"
6#include "ClipboardFreeRDP.h"
7#include <QLoggingCategory>
9#include <QRegularExpression>
16#if !(defined (Q_OS_WINDOWS) || defined(Q_OS_WIN) || defined(Q_OS_WIN32) || defined(Q_OS_WINRT))
22 FILEDESCRIPTORW fgd[1];
27QAtomicInteger<qint32> CClipboardMimeData::m_nId(1);
28static int g_UINT32 = qRegisterMetaType<UINT32>(
"UINT32");
30static Q_LOGGING_CATEGORY(log,
"FreeRDP.Clipboard.MimeData")
35 m_pClipboard(
nullptr),
41 qDebug(log) <<
"CClipboardMimeData::CClipboardMimeData:" << GetId();
44 m_pClipboard = pThis->m_pClipboard;
46 check = connect(
this, SIGNAL(sigRequestFileFromServer(
const QString&,
50 this, SLOT(slotRequestFileFromServer(
const QString&,
54 Qt::DirectConnection);
58CClipboardMimeData::~CClipboardMimeData()
60 qDebug(log) <<
"CClipboardMimeData::~CClipboardMimeData():" << GetId();
63 qDebug(log) <<
"CClipboardMimeData::~CClipboardMimeData() end:" << GetId();
66const qint32 CClipboardMimeData::GetId()
const
71int CClipboardMimeData::SetFormat(
const CLIPRDR_FORMAT_LIST *pList)
79 for (UINT32 i = 0; i < pList->numFormats; i++)
81 CLIPRDR_FORMAT* pFormat = &pList->formats[i];
85 AddFormat(pFormat->formatId, pFormat->formatName);
88 if(m_Formats.isEmpty())
92 for(
auto it = m_Formats.begin(); it != m_Formats.end(); it++)
95 szFormats += QString::number(it->id) +
"[";
96 szFormats += it->name;
99 m_indexId.insert(it->id, *it);
100 if(it->name.isEmpty())
108 m_indexString.insert(
"text/plain", *it);
115 m_indexString.insert(
"image/bmp", *it);
120 m_indexString.insert(
"text/uri-list", *it);
125 const char* name = ClipboardGetFormatName(m_pClipboard, it->id);
127 m_indexString.insert(name, *it);
131 m_indexString.insert(it->name, *it);
132 if(
"FileGroupDescriptorW" == it->name) {
134 m_indexString.insert(
"text/uri-list", *it);
136 m_indexString.insert(
"x-special/gnome-copied-files", *it);
138 }
else if(
"FileGroupDescriptor" == it->name) {
140 m_indexString.insert(
"text/uri-list", *it);
142 m_indexString.insert(
"x-special/gnome-copied-files", *it);
144 }
else if(
"UniformResourceLocatorW" == it->name) {
145 m_indexString.insert(
"text/uri-list", *it);
146 }
else if(
"UniformResourceLocator" == it->name) {
147 m_indexString.insert(
"text/uri-list", *it);
148 }
else if(
"x-special/gnome-copied-files" == it->name) {
149 m_indexString.insert(
"text/uri-list", *it);
150 }
else if(
"text/html" != it->name && isHtml(it->name,
false)) {
151 m_indexString.insert(
"text/html", *it);
152 }
else if(
"text/plain" != it->name && isText(it->name,
false)) {
153 m_indexString.insert(
"text/plain", *it);
154 }
else if(
"image/bmp" != it->name && isImage(it->name)) {
155 m_indexString.insert(
"image/bmp", *it);
160 m_lstFormats.clear();
161 for(
auto it = m_indexString.begin(); m_indexString.end() != it; it++)
163 if(!m_lstFormats.contains(it.key()))
164 m_lstFormats << (it.key());
166 if(m_lstFormats.contains(
"image/bmp")
167 && !m_lstFormats.contains(
"application/x-qt-image"))
169 m_lstFormats << (
"application/x-qt-image");
173 if(m_lstFormats.contains(
"text/uri-list")
174 && !m_lstFormats.contains(
"x-special/gnome-copied-files"))
176 m_lstFormats.push_front(
"x-special/gnome-copied-files");
177 m_lstFormats.removeOne(
"text/uri-list");
178 m_lstFormats.push_front(
"text/uri-list");
182 if(m_lstFormats.contains(
"text/uri-list")
183 && !m_lstFormats.contains(
"FileGroupDescriptorW"))
185 m_lstFormats.push_front(
"FileGroupDescriptorW");
186 m_lstFormats.removeOne(
"text/uri-list");
187 m_lstFormats.push_front(
"text/uri-list");
191 m_lstFormats << MIME_TYPE_RABBITREMOTECONTROL_PLUGINS_FREERDP;
193 qDebug(log) <<
"CClipboardMimeData::SetFormat: input formats:" << szFormats
194 <<
"Formats:" << m_lstFormats;
199int CClipboardMimeData::AddFormat(UINT32
id,
const char *name)
203 foreach(
auto it, m_Formats)
207 qWarning(log) <<
"Repeat format id:" << id;
215 qWarning(log) <<
"Repeat format name:" << name;
221 _FORMAT f = {id, name,
id};
224 f.localId = ClipboardRegisterFormat(m_pClipboard, name);
227 m_Formats.push_back(f);
232bool CClipboardMimeData::hasFormat(
const QString &mimetype)
const
235 qDebug(log) <<
"CClipboardMimeData::hasFormat:"
236 << mimetype.toStdString().c_str();
238 if(isImage(mimetype) && m_lstFormats.contains(
"image/bmp"))
240 if(isUrls(mimetype) && m_lstFormats.contains(
"text/uri-list"))
242 return m_lstFormats.contains(mimetype);
245QStringList CClipboardMimeData::formats()
const
252#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
253QVariant CClipboardMimeData::retrieveData(
const QString &mimeType,
254 QMetaType preferredType)
const
257QVariant CClipboardMimeData::retrieveData(
const QString &mimeType,
258 QVariant::Type preferredType)
const
262 qDebug(log) <<
"CClipboardMimeData::retrieveData:" << GetId() << mimeType
263 <<
"Variant:" << m_Variant;
264 if(MIME_TYPE_RABBITREMOTECONTROL_PLUGINS_FREERDP == mimeType)
267 QString mt = mimeType;
268 if(isImage(mt)) mt =
"image/bmp";
269 if(m_indexString.find(mt) == m_indexString.end())
273 auto lstValue = m_indexString.values(mt);
274 if(lstValue.isEmpty())
276 value = *lstValue.crbegin();
278 qDebug(log) <<
"CClipboardMimeData::retrieveData: format id:" << value.id
279 <<
"name:" << value.name <<
"mimeData:" << mimeType;
281 if(!m_pContext)
return QVariant();
283 emit sigSendDataRequest(m_pContext, value.id);
287 connect(
this, SIGNAL(sigContinue()), &loop, SLOT(quit()), Qt::DirectConnection);
289 qDebug(log) <<
"CClipboardMimeData::retrieveData end";
294 if(isUrls(mimeType) && !m_Variant.isNull())
296 QByteArray data = m_Variant.toByteArray();
297 emit sigRequestFileFromServer(mimeType, value.name, data.data(), data.size());
307 qDebug(log) <<
"CClipboardMimeData::slotServerFormatData: id:" << id;
312 if(!pData && 0 == nLen)
314 m_pContext =
nullptr;
318 if(m_indexId.find(
id) == m_indexId.end())
321 auto it = m_indexId[id];
327 dstId = ClipboardGetFormatId(m_pClipboard,
"image/bmp");
333 if(it.name.isEmpty())
336 if(isHtml(it.name,
false))
337 dstId = ClipboardGetFormatId(m_pClipboard,
"text/html");
343 bool bSuccess = ClipboardSetData(m_pClipboard, srcId, pData, nLen);
347 void* data = ClipboardGetData(m_pClipboard, dstId, &size);
350 qDebug(log) <<
"ClipboardGetData fail: dstId:" << dstId
351 <<
"srcId:" << srcId;
355 QByteArray d((
char*)data, size);
356 if(d.isEmpty())
break;
361 m_Variant = QString::fromLatin1(d);
367 m_Variant = QString::fromLocal8Bit(d);
375 m_Variant = QString::fromUtf16((
const char16_t*)data, size / 2);
379 if(
"UTF8_STRING" == it.name) {
380 m_Variant = QString::fromUtf8(d);
381 }
else if(isHtml(it.name)) {
382 m_Variant = QString(d);
383 }
else if(ClipboardGetFormatId(m_pClipboard,
"image/bmp") == dstId) {
385 if(img.loadFromData(d,
"BMP"))
388 m_Variant = QVariant(d);
395bool CClipboardMimeData::isText(QString mimeType,
bool bRegular)
const
398 if(
"UTF8_STRING" == mimeType)
return true;
399 if(
"TEXT" == mimeType)
return true;
400 if(
"STRING" == mimeType)
return true;
401 if(
"text/plain" == mimeType)
return true;
404 QRegularExpression re(
"text/plain[;]*.*",
405 QRegularExpression::CaseInsensitiveOption);
406 QRegularExpressionMatch match = re.match(mimeType);
413bool CClipboardMimeData::isHtml(QString mimeType,
bool bRegular)
const
417 if(
"text/html" == mimeType ||
"HTML Format" == mimeType)
423bool CClipboardMimeData::isUrls(QString mimeType,
bool bRegular)
const
427 if(
"FileGroupDescriptorW" == mimeType
428 ||
"FileGroupDescriptor" == mimeType
429 ||
"UniformResourceLocatorW" == mimeType
430 ||
"UniformResourceLocator" == mimeType
431 ||
"text/uri-list" == mimeType
432 ||
"x-special/gnome-copied-files" == mimeType)
438bool CClipboardMimeData::isImage(QString mimeType,
bool bRegular)
const
442 if(
"image/bmp" == mimeType)
return true;
444 if(
"application/x-qt-image" == mimeType)
return true;
447 QRegularExpression re(
"image/.*",
448 QRegularExpression::CaseInsensitiveOption);
449 QRegularExpressionMatch match = re.match(mimeType);
456void CClipboardMimeData::slotRequestFileFromServer(
const QString &mimeType,
457 const QString &valueName,
463 qDebug(log) <<
"CClipboardMimeData::slotRequestFileFromServer:"
464 << valueName << mimeType << pData;
465 if(!(
"FileGroupDescriptorW" == valueName
466 ||
"FileGroupDescriptor" == valueName))
469 int srcId = ClipboardGetFormatId(m_pClipboard, valueName.toStdString().c_str());
470 int dstId = ClipboardGetFormatId(m_pClipboard, mimeType.toStdString().c_str());
471 bool bSuccess = ClipboardSetData(m_pClipboard, srcId, pData, nLen);
473 qCritical(log) <<
"ClipboardSetData fail: dstId:" << dstId
474 <<
"srcId:" << srcId;
479 void* data = ClipboardGetData(m_pClipboard, dstId, &size);
481 qCritical(log) <<
"ClipboardGetData fail: dstId:" << dstId
482 <<
"srcId:" << srcId;
485 QString szFiles = QString::fromLatin1((
char*)data, size);
486 QStringList lstFile = szFiles.split(
"\n");
490 for(
int i = 0; i < pDes->cItems; i++)
492 QString szFile = lstFile[i].trimmed();
493 szFile = QUrl(szFile).toLocalFile();
494 QFileInfo fileInfo(szFile);
495 QDir d(fileInfo.absolutePath());
497 d.mkpath(fileInfo.absolutePath());
499 QSharedPointer<_CliprdrFileStream> stream
500 = QSharedPointer<_CliprdrFileStream>(
new _CliprdrFileStream());
501 stream->m_Success =
false;
502 stream->m_File.setFileName(szFile) ;
503 m_Stream.insert(i, stream);
505 if(pDes->fgd[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
508 UINT rc = sendRequestFilecontents(i, FILECONTENTS_SIZE, 0, 0, 8);
509 if(CHANNEL_RC_OK != rc)
513 if(stream->m_Data.isNull() || stream->m_Data.size() == 0)
515 ULARGE_INTEGER size, offset;
517 size.QuadPart = *((LONGLONG*)(stream->m_Data.data()));
518 if(size.QuadPart <= 0)
521 qDebug(log) <<
"File" << szFile
522 <<
";Length:" << size.u.HighPart << size.u.LowPart;
524 if(!stream->m_File.open(QFile::WriteOnly))
526 qCritical(log) <<
"Open file fail:" << szFile
527 << stream->m_File.errorString();
530 bool bSuccess =
true;
532 UINT32 nBlock = 2 << 15;
533 UINT32 nLen = size.QuadPart - offset.QuadPart;
537 rc = sendRequestFilecontents(i, FILECONTENTS_RANGE,
541 if(CHANNEL_RC_OK != rc)
546 if(stream->m_Data.isNull() || stream->m_Data.size() == 0)
552 stream->m_File.write(stream->m_Data);
553 offset.QuadPart += stream->m_Data.size();
554 }
while(offset.QuadPart < size.QuadPart);
555 stream->m_File.close();
557 stream->m_File.remove();
558 stream->m_Success = bSuccess;
563 if(
"x-special/gnome-copied-files" == mimeType)
565 QByteArray gnomeFormat;
566 gnomeFormat.append(
"copy\n");
568 foreach(
auto s, m_Stream)
577 fileName += QUrl::fromLocalFile(s->m_File.fileName()).toEncoded();
578 gnomeFormat.append(fileName.toStdString().c_str());
580 m_gnomeFiles = gnomeFormat;
581 m_Variant = gnomeFormat;
589 if(
"text/uri-list" == mimeType ||
"FileGroupDescriptorW" == mimeType)
591 QByteArray uriFormat;
592 foreach(
auto s, m_Stream)
597 fileName += QUrl::fromLocalFile(s->m_File.fileName()).toEncoded();
599 uriFormat.append(fileName.toStdString().c_str());
601 m_uriFiles = uriFormat;
602 m_Variant = uriFormat;
605 qDebug(log) <<
"CClipboardMimeData::slotRequestFileFromServer::QVariant:" << m_Variant;
610UINT CClipboardMimeData::sendRequestFilecontents(UINT32 listIndex,
617 qDebug(log) <<
"CClipboardMimeData::sendRequestFilecontents";
618 UINT rc = ERROR_INTERNAL_ERROR;
619 if(!m_pContext)
return rc;
621 CLIPRDR_FILE_CONTENTS_REQUEST fileContentsRequest = {0};
622 fileContentsRequest.streamId = listIndex;
623 fileContentsRequest.listIndex = listIndex;
624 fileContentsRequest.dwFlags = dwFlags;
635 case FILECONTENTS_SIZE:
636 fileContentsRequest.cbRequested =
sizeof(UINT64);
637 fileContentsRequest.nPositionHigh = 0;
638 fileContentsRequest.nPositionLow = 0;
640 case FILECONTENTS_RANGE:
641 fileContentsRequest.cbRequested = cbRequested;
642 fileContentsRequest.nPositionHigh = nPositionHigh;
643 fileContentsRequest.nPositionLow = nPositionLow;
646 rc = m_pContext->ClientFileContentsRequest(m_pContext, &fileContentsRequest);
650 connect(
this, SIGNAL(sigContinue()), &loop, SLOT(quit()), Qt::DirectConnection);
655 return CHANNEL_RC_NULL_DATA;
660void CClipboardMimeData::slotServerFileContentsRespose(UINT32 streamId,
664 qDebug(log) <<
"CClipboardMimeData::slotServerFileContentsRespose: index:"
665 << streamId <<
";Data length:" << data.size();
666 auto stream = m_Stream.find(streamId);
668 if(m_Stream.end() == stream || data.isNull())
670 QSharedPointer<_CliprdrFileStream> s = *stream;
void slotServerFormatData(const BYTE *pData, UINT32 nLen, UINT32 id)
if(pData == nullptr && nLen == 0) is Notify clipboard program has exited