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_Variant.isValid() && !m_Variant.isNull()) {
284 QByteArray data = m_Variant.toByteArray();
285 emit sigRequestFileFromServer(mimeType, value.name, data.data(), data.size());
289 if(!m_pContext)
return QVariant();
291 emit sigSendDataRequest(m_pContext, value.id);
295 connect(
this, SIGNAL(sigContinue()), &loop, SLOT(quit()), Qt::DirectConnection);
297 qDebug(log) <<
"CClipboardMimeData::retrieveData end";
302 if(isUrls(mimeType) && !m_Variant.isNull())
304 QByteArray data = m_Variant.toByteArray();
305 emit sigRequestFileFromServer(mimeType, value.name, data.data(), data.size());
315 qDebug(log) <<
"CClipboardMimeData::slotServerFormatData: id:" << id;
320 if(!pData && 0 == nLen)
322 m_pContext =
nullptr;
326 if(m_indexId.find(
id) == m_indexId.end())
329 auto it = m_indexId[id];
335 dstId = ClipboardGetFormatId(m_pClipboard,
"image/bmp");
341 if(it.name.isEmpty())
344 if(isHtml(it.name,
false))
345 dstId = ClipboardGetFormatId(m_pClipboard,
"text/html");
351 bool bSuccess = ClipboardSetData(m_pClipboard, srcId, pData, nLen);
355 void* data = ClipboardGetData(m_pClipboard, dstId, &size);
358 qDebug(log) <<
"ClipboardGetData fail: dstId:" << dstId
359 <<
"srcId:" << srcId;
363 QByteArray d((
char*)data, size);
364 if(d.isEmpty())
break;
369 m_Variant = QString::fromLatin1(d);
375 m_Variant = QString::fromLocal8Bit(d);
383 m_Variant = QString::fromUtf16((
const char16_t*)data, size / 2);
387 if(
"UTF8_STRING" == it.name) {
388 m_Variant = QString::fromUtf8(d);
389 }
else if(isHtml(it.name)) {
390 m_Variant = QString(d);
391 }
else if(ClipboardGetFormatId(m_pClipboard,
"image/bmp") == dstId) {
393 if(img.loadFromData(d,
"BMP"))
396 m_Variant = QVariant(d);
403bool CClipboardMimeData::isText(QString mimeType,
bool bRegular)
const
406 if(
"UTF8_STRING" == mimeType)
return true;
407 if(
"TEXT" == mimeType)
return true;
408 if(
"STRING" == mimeType)
return true;
409 if(
"text/plain" == mimeType)
return true;
412 QRegularExpression re(
"text/plain[;]*.*",
413 QRegularExpression::CaseInsensitiveOption);
414 QRegularExpressionMatch match = re.match(mimeType);
421bool CClipboardMimeData::isHtml(QString mimeType,
bool bRegular)
const
425 if(
"text/html" == mimeType ||
"HTML Format" == mimeType)
431bool CClipboardMimeData::isUrls(QString mimeType,
bool bRegular)
const
435 if(
"FileGroupDescriptorW" == mimeType
436 ||
"FileGroupDescriptor" == mimeType
437 ||
"UniformResourceLocatorW" == mimeType
438 ||
"UniformResourceLocator" == mimeType
439 ||
"text/uri-list" == mimeType
440 ||
"x-special/gnome-copied-files" == mimeType)
446bool CClipboardMimeData::isImage(QString mimeType,
bool bRegular)
const
450 if(
"image/bmp" == mimeType)
return true;
452 if(
"application/x-qt-image" == mimeType)
return true;
455 QRegularExpression re(
"image/.*",
456 QRegularExpression::CaseInsensitiveOption);
457 QRegularExpressionMatch match = re.match(mimeType);
464void CClipboardMimeData::slotRequestFileFromServer(
const QString &mimeType,
465 const QString &valueName,
471 qDebug(log) <<
"CClipboardMimeData::slotRequestFileFromServer:"
472 << valueName << mimeType << pData;
473 if(!(
"FileGroupDescriptorW" == valueName
474 ||
"FileGroupDescriptor" == valueName))
477 int srcId = ClipboardGetFormatId(m_pClipboard, valueName.toStdString().c_str());
478 int dstId = ClipboardGetFormatId(m_pClipboard, mimeType.toStdString().c_str());
479 bool bSuccess = ClipboardSetData(m_pClipboard, srcId, pData, nLen);
481 qCritical(log) <<
"ClipboardSetData fail: dstId:" << dstId
482 <<
"srcId:" << srcId;
487 void* data = ClipboardGetData(m_pClipboard, dstId, &size);
489 qCritical(log) <<
"ClipboardGetData fail: dstId:" << dstId
490 <<
"srcId:" << srcId;
493 QString szFiles = QString::fromLatin1((
char*)data, size);
494 QStringList lstFile = szFiles.split(
"\n");
498 for(
int i = 0; i < pDes->cItems; i++)
500 QString szFile = lstFile[i].trimmed();
501 szFile = QUrl(szFile).toLocalFile();
502 QFileInfo fileInfo(szFile);
503 QDir d(fileInfo.absolutePath());
505 d.mkpath(fileInfo.absolutePath());
507 QSharedPointer<_CliprdrFileStream> stream
508 = QSharedPointer<_CliprdrFileStream>(
new _CliprdrFileStream());
509 stream->m_Success =
false;
510 stream->m_File.setFileName(szFile) ;
511 m_Stream.insert(i, stream);
513 if(pDes->fgd[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
516 UINT rc = sendRequestFilecontents(i, FILECONTENTS_SIZE, 0, 0, 8);
517 if(CHANNEL_RC_OK != rc)
521 if(stream->m_Data.isNull() || stream->m_Data.size() == 0)
523 ULARGE_INTEGER size, offset;
525 size.QuadPart = *((LONGLONG*)(stream->m_Data.data()));
526 if(size.QuadPart <= 0)
529 qDebug(log) <<
"File" << szFile
530 <<
";Length:" << size.u.HighPart << size.u.LowPart;
532 if(!stream->m_File.open(QFile::WriteOnly))
534 qCritical(log) <<
"Open file fail:" << szFile
535 << stream->m_File.errorString();
538 bool bSuccess =
true;
540 UINT32 nBlock = 2 << 15;
541 UINT32 nLen = size.QuadPart - offset.QuadPart;
545 rc = sendRequestFilecontents(i, FILECONTENTS_RANGE,
549 if(CHANNEL_RC_OK != rc)
554 if(stream->m_Data.isNull() || stream->m_Data.size() == 0)
560 stream->m_File.write(stream->m_Data);
561 offset.QuadPart += stream->m_Data.size();
562 }
while(offset.QuadPart < size.QuadPart);
563 stream->m_File.close();
565 stream->m_File.remove();
566 stream->m_Success = bSuccess;
571 if(
"x-special/gnome-copied-files" == mimeType)
573 QByteArray gnomeFormat;
574 gnomeFormat.append(
"copy\n");
576 foreach(
auto s, m_Stream)
585 fileName += QUrl::fromLocalFile(s->m_File.fileName()).toEncoded();
586 gnomeFormat.append(fileName.toStdString().c_str());
588 m_gnomeFiles = gnomeFormat;
589 m_Variant = gnomeFormat;
597 if(
"text/uri-list" == mimeType ||
"FileGroupDescriptorW" == mimeType)
599 QByteArray uriFormat;
600 foreach(
auto s, m_Stream)
605 fileName += QUrl::fromLocalFile(s->m_File.fileName()).toEncoded();
607 uriFormat.append(fileName.toStdString().c_str());
609 m_uriFiles = uriFormat;
610 m_Variant = uriFormat;
613 qDebug(log) <<
"CClipboardMimeData::slotRequestFileFromServer::QVariant:" << m_Variant;
618UINT CClipboardMimeData::sendRequestFilecontents(UINT32 listIndex,
625 qDebug(log) <<
"CClipboardMimeData::sendRequestFilecontents";
626 UINT rc = ERROR_INTERNAL_ERROR;
627 if(!m_pContext)
return rc;
629 CLIPRDR_FILE_CONTENTS_REQUEST fileContentsRequest = {0};
630 fileContentsRequest.streamId = listIndex;
631 fileContentsRequest.listIndex = listIndex;
632 fileContentsRequest.dwFlags = dwFlags;
643 case FILECONTENTS_SIZE:
644 fileContentsRequest.cbRequested =
sizeof(UINT64);
645 fileContentsRequest.nPositionHigh = 0;
646 fileContentsRequest.nPositionLow = 0;
648 case FILECONTENTS_RANGE:
649 fileContentsRequest.cbRequested = cbRequested;
650 fileContentsRequest.nPositionHigh = nPositionHigh;
651 fileContentsRequest.nPositionLow = nPositionLow;
654 rc = m_pContext->ClientFileContentsRequest(m_pContext, &fileContentsRequest);
658 connect(
this, SIGNAL(sigContinue()), &loop, SLOT(quit()), Qt::DirectConnection);
663 return CHANNEL_RC_NULL_DATA;
668void CClipboardMimeData::slotServerFileContentsRespose(UINT32 streamId,
672 qDebug(log) <<
"CClipboardMimeData::slotServerFileContentsRespose: index:"
673 << streamId <<
";Data length:" << data.size();
674 auto stream = m_Stream.find(streamId);
676 if(m_Stream.end() == stream || data.isNull())
678 QSharedPointer<_CliprdrFileStream> s = *stream;
void slotServerFormatData(const BYTE *pData, UINT32 nLen, UINT32 id)
if(pData == nullptr && nLen == 0) is Notify clipboard program has exited