src/gui/kernel/qmime_win.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
child 7 f7bc934e204c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qmime.h"
       
    43 
       
    44 #include "qimagereader.h"
       
    45 #include "qimagewriter.h"
       
    46 #include "qdatastream.h"
       
    47 #include "qbuffer.h"
       
    48 #include "qt_windows.h"
       
    49 #include "qapplication_p.h"
       
    50 #include "qtextcodec.h"
       
    51 #include "qregexp.h"
       
    52 #include "qalgorithms.h"
       
    53 #include "qmap.h"
       
    54 #include "qdnd_p.h"
       
    55 #include <shlobj.h>
       
    56 #include "qurl.h"
       
    57 #include "qvariant.h"
       
    58 #include "qtextdocument.h"
       
    59 #include "qdir.h"
       
    60 
       
    61 #if defined(Q_OS_WINCE)
       
    62 #include "qguifunctions_wince.h"
       
    63 #endif
       
    64 
       
    65 QT_BEGIN_NAMESPACE
       
    66 
       
    67 #ifndef QT_NO_IMAGEFORMAT_BMP
       
    68 #ifndef CF_DIBV5
       
    69 #define CF_DIBV5 17
       
    70 #endif
       
    71 /* The MSVC compilers allows multi-byte characters, that has the behavior of
       
    72  * that each character gets shifted into position. 0x73524742 below is for MSVC
       
    73  * equivalent to doing 'sRGB', but this does of course not work
       
    74  * on conformant C++ compilers. */
       
    75 #define BMP_LCS_sRGB  0x73524742
       
    76 #define BMP_LCS_GM_IMAGES  0x00000004L
       
    77 
       
    78 struct _CIEXYZ {
       
    79     long ciexyzX, ciexyzY, ciexyzZ;
       
    80 };
       
    81 
       
    82 struct _CIEXYZTRIPLE {
       
    83     _CIEXYZ  ciexyzRed, ciexyzGreen, ciexyzBlue;
       
    84 };
       
    85 
       
    86 struct BMP_BITMAPV5HEADER {
       
    87     DWORD  bV5Size;
       
    88     LONG   bV5Width;
       
    89     LONG   bV5Height;
       
    90     WORD   bV5Planes;
       
    91     WORD   bV5BitCount;
       
    92     DWORD  bV5Compression;
       
    93     DWORD  bV5SizeImage;
       
    94     LONG   bV5XPelsPerMeter;
       
    95     LONG   bV5YPelsPerMeter;
       
    96     DWORD  bV5ClrUsed;
       
    97     DWORD  bV5ClrImportant;
       
    98     DWORD  bV5RedMask;
       
    99     DWORD  bV5GreenMask;
       
   100     DWORD  bV5BlueMask;
       
   101     DWORD  bV5AlphaMask;
       
   102     DWORD  bV5CSType;
       
   103     _CIEXYZTRIPLE bV5Endpoints;
       
   104     DWORD  bV5GammaRed;
       
   105     DWORD  bV5GammaGreen;
       
   106     DWORD  bV5GammaBlue;
       
   107     DWORD  bV5Intent;
       
   108     DWORD  bV5ProfileData;
       
   109     DWORD  bV5ProfileSize;
       
   110     DWORD  bV5Reserved;
       
   111 };
       
   112 static const int BMP_BITFIELDS = 3;
       
   113 
       
   114 extern bool qt_read_dib(QDataStream&, QImage&); // qimage.cpp
       
   115 extern bool qt_write_dib(QDataStream&, QImage);   // qimage.cpp
       
   116 static bool qt_write_dibv5(QDataStream &s, QImage image);
       
   117 static bool qt_read_dibv5(QDataStream &s, QImage &image);
       
   118 #endif
       
   119 
       
   120 //#define QMIME_DEBUG
       
   121 
       
   122 
       
   123 // helpers for using global memory
       
   124 
       
   125 static int getCf(const FORMATETC &formatetc)
       
   126 {
       
   127     return formatetc.cfFormat;
       
   128 }
       
   129 
       
   130 static FORMATETC setCf(int cf)
       
   131 {
       
   132     FORMATETC formatetc;
       
   133     formatetc.cfFormat = cf;
       
   134     formatetc.dwAspect = DVASPECT_CONTENT;
       
   135     formatetc.lindex = -1;
       
   136     formatetc.ptd = NULL;
       
   137     formatetc.tymed = TYMED_HGLOBAL;
       
   138     return formatetc;
       
   139 }
       
   140 
       
   141 static bool setData(const QByteArray &data, STGMEDIUM *pmedium)
       
   142 {
       
   143     HGLOBAL hData = GlobalAlloc(0, data.size());
       
   144     if (!hData)
       
   145         return false;
       
   146 
       
   147     void *out = GlobalLock(hData);
       
   148     memcpy(out, data.data(), data.size());
       
   149     GlobalUnlock(hData);
       
   150     pmedium->tymed = TYMED_HGLOBAL;
       
   151     pmedium->hGlobal = hData;
       
   152     pmedium->pUnkForRelease = 0;
       
   153     return true;
       
   154 }
       
   155 
       
   156 static QByteArray getData(int cf, IDataObject *pDataObj)
       
   157 {
       
   158     QByteArray data;
       
   159     FORMATETC formatetc = setCf(cf);
       
   160     STGMEDIUM s;
       
   161     if (pDataObj->GetData(&formatetc, &s) == S_OK) {
       
   162         DWORD * val = (DWORD*)GlobalLock(s.hGlobal);
       
   163         data = QByteArray::fromRawData((char*)val, GlobalSize(s.hGlobal));
       
   164         data.detach();
       
   165         GlobalUnlock(s.hGlobal);
       
   166         ReleaseStgMedium(&s);
       
   167     } else  {
       
   168         //Try reading IStream data
       
   169         formatetc.tymed = TYMED_ISTREAM;
       
   170         if (pDataObj->GetData(&formatetc, &s) == S_OK) {
       
   171             char szBuffer[4096];
       
   172             ULONG actualRead = 0;
       
   173             LARGE_INTEGER pos = {{0, 0}};
       
   174             //Move to front (can fail depending on the data model implemented)
       
   175             HRESULT hr = s.pstm->Seek(pos, STREAM_SEEK_SET, NULL);
       
   176             while(SUCCEEDED(hr)){
       
   177                 hr = s.pstm->Read(szBuffer, sizeof(szBuffer), &actualRead);
       
   178                 if (SUCCEEDED(hr) && actualRead > 0) {
       
   179                     data += QByteArray::fromRawData(szBuffer, actualRead);
       
   180                 }
       
   181                 if (actualRead != sizeof(szBuffer))
       
   182                     break;
       
   183             }
       
   184             data.detach();
       
   185             ReleaseStgMedium(&s);
       
   186         }
       
   187     }
       
   188     return data;
       
   189 }
       
   190 
       
   191 static bool canGetData(int cf, IDataObject * pDataObj)
       
   192 {
       
   193     FORMATETC formatetc = setCf(cf);
       
   194      if (pDataObj->QueryGetData(&formatetc) != S_OK){
       
   195         formatetc.tymed = TYMED_ISTREAM;
       
   196         return pDataObj->QueryGetData(&formatetc) == S_OK;
       
   197     }
       
   198     return true;
       
   199 }
       
   200 
       
   201 class QWindowsMimeList
       
   202 {
       
   203 public:
       
   204     QWindowsMimeList();
       
   205     ~QWindowsMimeList();
       
   206     void addWindowsMime(QWindowsMime * mime);
       
   207     void removeWindowsMime(QWindowsMime * mime);
       
   208     QList<QWindowsMime*> windowsMimes();
       
   209 
       
   210 private:
       
   211     void init();
       
   212     bool initialized;
       
   213     QList<QWindowsMime*> mimes;
       
   214 };
       
   215 
       
   216 Q_GLOBAL_STATIC(QWindowsMimeList, theMimeList);
       
   217 
       
   218 
       
   219 /*!
       
   220     \class QWindowsMime
       
   221     \brief The QWindowsMime class maps open-standard MIME to Window Clipboard formats.
       
   222     \ingroup draganddrop
       
   223 
       
   224     Qt's drag-and-drop and clipboard facilities use the MIME standard.
       
   225     On X11, this maps trivially to the Xdnd protocol, but on Windows
       
   226     although some applications use MIME types to describe clipboard
       
   227     formats, others use arbitrary non-standardized naming conventions,
       
   228     or unnamed built-in formats of Windows.
       
   229 
       
   230     By instantiating subclasses of QWindowsMime that provide conversions
       
   231     between Windows Clipboard and MIME formats, you can convert
       
   232     proprietary clipboard formats to MIME formats.
       
   233 
       
   234     Qt has predefined support for the following Windows Clipboard formats:
       
   235 
       
   236     \table
       
   237     \header \o Windows Format \o Equivalent MIME type
       
   238     \row \o \c CF_UNICODETEXT \o \c text/plain
       
   239     \row \o \c CF_TEXT        \o \c text/plain
       
   240     \row \o \c CF_DIB         \o \c{image/xyz}, where \c xyz is
       
   241                                  a \l{QImageWriter::supportedImageFormats()}{Qt image format}
       
   242     \row \o \c CF_HDROP       \o \c text/uri-list
       
   243     \row \o \c CF_INETURL     \o \c text/uri-list
       
   244     \row \o \c CF_HTML        \o \c text/html
       
   245     \endtable
       
   246 
       
   247     An example use of this class would be to map the Windows Metafile
       
   248     clipboard format (\c CF_METAFILEPICT) to and from the MIME type
       
   249     \c{image/x-wmf}. This conversion might simply be adding or removing
       
   250     a header, or even just passing on the data. See \l{Drag and Drop}
       
   251     for more information on choosing and definition MIME types.
       
   252 
       
   253     You can check if a MIME type is convertible using canConvertFromMime() and
       
   254     can perform conversions with convertToMime() and convertFromMime().
       
   255 */
       
   256 
       
   257 /*!
       
   258 Constructs a new conversion object, adding it to the globally accessed
       
   259 list of available converters.
       
   260 */
       
   261 QWindowsMime::QWindowsMime()
       
   262 {
       
   263     theMimeList()->addWindowsMime(this);
       
   264 }
       
   265 
       
   266 /*!
       
   267 Destroys a conversion object, removing it from the global
       
   268 list of available converters.
       
   269 */
       
   270 QWindowsMime::~QWindowsMime()
       
   271 {
       
   272     theMimeList()->removeWindowsMime(this);
       
   273 }
       
   274 
       
   275 
       
   276 /*!
       
   277     Registers the MIME type \a mime, and returns an ID number
       
   278     identifying the format on Windows.
       
   279 */
       
   280 int QWindowsMime::registerMimeType(const QString &mime)
       
   281 {
       
   282     int f = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (mime.utf16()));
       
   283     if (!f)
       
   284         qErrnoWarning("QWindowsMime::registerMimeType: Failed to register clipboard format");
       
   285 
       
   286     return f;
       
   287 }
       
   288 
       
   289 
       
   290 /*!
       
   291 \fn bool QWindowsMime::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
       
   292 
       
   293   Returns true if the converter can convert from the \a mimeData to
       
   294   the format specified in \a formatetc.
       
   295 
       
   296   All subclasses must reimplement this pure virtual function.
       
   297 */
       
   298 
       
   299 /*!
       
   300   \fn bool QWindowsMime::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
       
   301 
       
   302   Returns true if the converter can convert to the \a mimeType from
       
   303   the available formats in \a pDataObj.
       
   304 
       
   305   All subclasses must reimplement this pure virtual function.
       
   306 */
       
   307 
       
   308 /*!
       
   309 \fn QString QWindowsMime::mimeForFormat(const FORMATETC &formatetc) const
       
   310 
       
   311   Returns the mime type that will be created form the format specified
       
   312   in \a formatetc, or an empty string if this converter does not support
       
   313   \a formatetc.
       
   314 
       
   315   All subclasses must reimplement this pure virtual function.
       
   316 */
       
   317 
       
   318 /*!
       
   319 \fn QVector<FORMATETC> QWindowsMime::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
       
   320 
       
   321   Returns a QVector of FORMATETC structures representing the different windows clipboard
       
   322   formats that can be provided for the \a mimeType from the \a mimeData.
       
   323 
       
   324   All subclasses must reimplement this pure virtual function.
       
   325 */
       
   326 
       
   327 /*!
       
   328     \fn QVariant QWindowsMime::convertToMime(const QString &mimeType, IDataObject *pDataObj,
       
   329                                              QVariant::Type preferredType) const
       
   330 
       
   331     Returns a QVariant containing the converted data for \a mimeType from \a pDataObj.
       
   332     If possible the QVariant should be of the \a preferredType to avoid needless conversions.
       
   333 
       
   334     All subclasses must reimplement this pure virtual function.
       
   335 */
       
   336 
       
   337 /*!
       
   338 \fn bool QWindowsMime::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
       
   339 
       
   340   Convert the \a mimeData to the format specified in \a formatetc.
       
   341   The converted data should then be placed in \a pmedium structure.
       
   342 
       
   343   Return true if the conversion was successful.
       
   344 
       
   345   All subclasses must reimplement this pure virtual function.
       
   346 */
       
   347 
       
   348 
       
   349 QWindowsMime *QWindowsMime::converterFromMime(const FORMATETC &formatetc, const QMimeData *mimeData)
       
   350 {
       
   351     QList<QWindowsMime*> mimes = theMimeList()->windowsMimes();
       
   352     for (int i=mimes.size()-1; i>=0; --i) {
       
   353         if (mimes.at(i)->canConvertFromMime(formatetc, mimeData))
       
   354             return mimes.at(i);
       
   355     }
       
   356     return 0;
       
   357 }
       
   358 
       
   359 QWindowsMime *QWindowsMime::converterToMime(const QString &mimeType, IDataObject *pDataObj)
       
   360 {
       
   361     QList<QWindowsMime*> mimes = theMimeList()->windowsMimes();
       
   362     for (int i=mimes.size()-1; i>=0; --i) {
       
   363         if (mimes.at(i)->canConvertToMime(mimeType, pDataObj))
       
   364             return mimes.at(i);
       
   365     }
       
   366     return 0;
       
   367 }
       
   368 
       
   369 QVector<FORMATETC> QWindowsMime::allFormatsForMime(const QMimeData *mimeData)
       
   370 {
       
   371     QList<QWindowsMime*> mimes = theMimeList()->windowsMimes();
       
   372     QVector<FORMATETC> formatics;
       
   373     formatics.reserve(20);
       
   374 #ifndef QT_NO_DRAGANDDROP
       
   375     QStringList formats = QInternalMimeData::formatsHelper(mimeData);
       
   376     for (int f=0; f<formats.size(); ++f) {
       
   377         for (int i=mimes.size()-1; i>=0; --i)
       
   378             formatics += mimes.at(i)->formatsForMime(formats.at(f), mimeData);
       
   379     }
       
   380 #else
       
   381     Q_UNUSED(mimeData);
       
   382 #endif //QT_NO_DRAGANDDROP
       
   383     return formatics;
       
   384 }
       
   385 
       
   386 QStringList QWindowsMime::allMimesForFormats(IDataObject *pDataObj)
       
   387 {
       
   388     QList<QWindowsMime*> mimes = theMimeList()->windowsMimes();
       
   389     QStringList formats;
       
   390     LPENUMFORMATETC FAR fmtenum;
       
   391     HRESULT hr = pDataObj->EnumFormatEtc(DATADIR_GET, &fmtenum);
       
   392 
       
   393     if (hr == NOERROR) {
       
   394         FORMATETC fmtetc;
       
   395         while (S_OK == fmtenum->Next(1, &fmtetc, 0)) {
       
   396 #if defined(QMIME_DEBUG) && !defined(Q_OS_WINCE)
       
   397             qDebug("QWindowsMime::allMimesForFormats()");
       
   398             wchar_t buf[256] = {0};
       
   399             GetClipboardFormatName(fmtetc.cfFormat, buf, 255);
       
   400             qDebug("CF = %d : %s", fmtetc.cfFormat, QString::fromWCharArray(buf));
       
   401 #endif
       
   402             for (int i=mimes.size()-1; i>=0; --i) {
       
   403                 QString format = mimes.at(i)->mimeForFormat(fmtetc);
       
   404                 if (!format.isEmpty() && !formats.contains(format)) {
       
   405                     formats += format;
       
   406                 }
       
   407             }
       
   408             // as documented in MSDN to avoid possible memleak
       
   409             if (fmtetc.ptd)
       
   410                 CoTaskMemFree(fmtetc.ptd);
       
   411         }
       
   412         fmtenum->Release();
       
   413     }
       
   414 
       
   415     return formats;
       
   416 }
       
   417 
       
   418 
       
   419 class QWindowsMimeText : public QWindowsMime
       
   420 {
       
   421 public:
       
   422     bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
       
   423     QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const;
       
   424     QString mimeForFormat(const FORMATETC &formatetc) const;
       
   425     bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
       
   426     bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const;
       
   427     QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
       
   428 };
       
   429 
       
   430 bool QWindowsMimeText::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
       
   431 {
       
   432     int cf = getCf(formatetc);
       
   433     return (cf == CF_UNICODETEXT || cf == CF_TEXT) && mimeData->hasText();
       
   434 }
       
   435 
       
   436 /*
       
   437 text/plain is defined as using CRLF, but so many programs don't,
       
   438 and programmers just look for '\n' in strings.
       
   439 Windows really needs CRLF, so we ensure it here.
       
   440 */
       
   441 bool QWindowsMimeText::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const
       
   442 {
       
   443     if (canConvertFromMime(formatetc, mimeData)) {
       
   444         QByteArray data;
       
   445         int cf = getCf(formatetc);
       
   446         if (cf == CF_TEXT) {
       
   447             data = mimeData->text().toLocal8Bit();
       
   448             // Anticipate required space for CRLFs at 1/40
       
   449             int maxsize=data.size()+data.size()/40+3;
       
   450             QByteArray r(maxsize, '\0');
       
   451             char* o = r.data();
       
   452             const char* d = data.data();
       
   453             const int s = data.size();
       
   454             bool cr=false;
       
   455             int j=0;
       
   456             for (int i=0; i<s; i++) {
       
   457                 char c = d[i];
       
   458                 if (c=='\r')
       
   459                     cr=true;
       
   460                 else {
       
   461                     if (c=='\n') {
       
   462                         if (!cr)
       
   463                             o[j++]='\r';
       
   464                     }
       
   465                     cr=false;
       
   466                 }
       
   467                 o[j++]=c;
       
   468                 if (j+3 >= maxsize) {
       
   469                     maxsize += maxsize/4;
       
   470                     r.resize(maxsize);
       
   471                     o = r.data();
       
   472                 }
       
   473             }
       
   474             o[j]=0;
       
   475             return setData(r, pmedium);
       
   476         } else if (cf == CF_UNICODETEXT) {
       
   477             QString str = mimeData->text();
       
   478             const QChar *u = str.unicode();
       
   479             QString res;
       
   480             const int s = str.length();
       
   481             int maxsize = s + s/40 + 3;
       
   482             res.resize(maxsize);
       
   483             int ri = 0;
       
   484             bool cr = false;
       
   485             for (int i=0; i < s; ++i) {
       
   486                 if (*u == QLatin1Char('\r'))
       
   487                     cr = true;
       
   488                 else {
       
   489                     if (*u == QLatin1Char('\n') && !cr)
       
   490                         res[ri++] = QLatin1Char('\r');
       
   491                     cr = false;
       
   492                 }
       
   493                 res[ri++] = *u;
       
   494                 if (ri+3 >= maxsize) {
       
   495                     maxsize += maxsize/4;
       
   496                     res.resize(maxsize);
       
   497                 }
       
   498                 ++u;
       
   499             }
       
   500             res.truncate(ri);
       
   501             const int byteLength = res.length() * sizeof(ushort);
       
   502             QByteArray r(byteLength + 2, '\0');
       
   503             memcpy(r.data(), res.unicode(), byteLength);
       
   504             r[byteLength] = 0;
       
   505             r[byteLength+1] = 0;
       
   506             return setData(r, pmedium);
       
   507         }
       
   508     }
       
   509     return false;
       
   510 }
       
   511 
       
   512 bool QWindowsMimeText::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
       
   513 {
       
   514     return mimeType.startsWith(QLatin1String("text/plain"))
       
   515            && (canGetData(CF_UNICODETEXT, pDataObj)
       
   516            || canGetData(CF_TEXT, pDataObj));
       
   517 }
       
   518 
       
   519 QString QWindowsMimeText::mimeForFormat(const FORMATETC &formatetc) const
       
   520 {
       
   521     int cf = getCf(formatetc);
       
   522     if (cf == CF_UNICODETEXT || cf == CF_TEXT)
       
   523         return QLatin1String("text/plain");
       
   524     return QString();
       
   525 }
       
   526 
       
   527 
       
   528 QVector<FORMATETC> QWindowsMimeText::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
       
   529 {
       
   530     QVector<FORMATETC> formatics;
       
   531     if (mimeType.startsWith(QLatin1String("text/plain")) && mimeData->hasText()) {
       
   532         formatics += setCf(CF_UNICODETEXT);
       
   533         formatics += setCf(CF_TEXT);
       
   534     }
       
   535     return formatics;
       
   536 }
       
   537 
       
   538 QVariant QWindowsMimeText::convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const
       
   539 {
       
   540     QVariant ret;
       
   541 
       
   542     if (canConvertToMime(mime, pDataObj)) {
       
   543         QString str;
       
   544         QByteArray data = getData(CF_UNICODETEXT, pDataObj);
       
   545         if (!data.isEmpty()) {
       
   546             str = QString::fromWCharArray((const wchar_t *)data.data());
       
   547             str.replace(QLatin1String("\r\n"), QLatin1String("\n"));
       
   548         } else {
       
   549             data = getData(CF_TEXT, pDataObj);
       
   550             if (!data.isEmpty()) {
       
   551                 const char* d = data.data();
       
   552                 const int s = qstrlen(d);
       
   553                 QByteArray r(data.size()+1, '\0');
       
   554                 char* o = r.data();
       
   555                 int j=0;
       
   556                 for (int i=0; i<s; i++) {
       
   557                     char c = d[i];
       
   558                     if (c!='\r')
       
   559                         o[j++]=c;
       
   560                 }
       
   561                 o[j]=0;
       
   562                 str = QString::fromLocal8Bit(r);
       
   563             }
       
   564         }
       
   565         if (preferredType == QVariant::String)
       
   566             ret = str;
       
   567         else
       
   568             ret = str.toUtf8();
       
   569     }
       
   570 
       
   571     return ret;
       
   572 }
       
   573 
       
   574 class QWindowsMimeURI : public QWindowsMime
       
   575 {
       
   576 public:
       
   577     QWindowsMimeURI();
       
   578     bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
       
   579     QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const;
       
   580     QString mimeForFormat(const FORMATETC &formatetc) const;
       
   581     bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
       
   582     bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const;
       
   583     QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
       
   584 private:
       
   585     int CF_INETURL_W; // wide char version
       
   586     int CF_INETURL;
       
   587 };
       
   588 
       
   589 QWindowsMimeURI::QWindowsMimeURI()
       
   590 {
       
   591     CF_INETURL_W = QWindowsMime::registerMimeType(QLatin1String("UniformResourceLocatorW"));
       
   592     CF_INETURL = QWindowsMime::registerMimeType(QLatin1String("UniformResourceLocator"));
       
   593 }
       
   594 
       
   595 bool QWindowsMimeURI::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
       
   596 {
       
   597     if (getCf(formatetc) == CF_HDROP) {
       
   598         QList<QUrl> urls = mimeData->urls();
       
   599         for (int i=0; i<urls.size(); i++) {
       
   600             if (!urls.at(i).toLocalFile().isEmpty())
       
   601                 return true;
       
   602         }
       
   603     }
       
   604     return (getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL) && mimeData->hasFormat(QLatin1String("text/uri-list"));
       
   605 }
       
   606 
       
   607 bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const
       
   608 {
       
   609     if (canConvertFromMime(formatetc, mimeData)) {
       
   610         if (getCf(formatetc) == CF_HDROP) {
       
   611             QList<QUrl> urls = mimeData->urls();
       
   612             QStringList fileNames;
       
   613             int size = sizeof(DROPFILES)+2;
       
   614             for (int i=0; i<urls.size(); i++) {
       
   615                 QString fn = QDir::toNativeSeparators(urls.at(i).toLocalFile());
       
   616                 if (!fn.isEmpty()) {
       
   617                     size += sizeof(ushort) * (fn.length() + 1);
       
   618                     fileNames.append(fn);
       
   619                 }
       
   620             }
       
   621 
       
   622             QByteArray result(size, '\0');
       
   623             DROPFILES* d = (DROPFILES*)result.data();
       
   624             d->pFiles = sizeof(DROPFILES);
       
   625             GetCursorPos(&d->pt); // try
       
   626             d->fNC = true;
       
   627             char* files = ((char*)d) + d->pFiles;
       
   628 
       
   629             d->fWide = true;
       
   630             wchar_t* f = (wchar_t*)files;
       
   631             for (int i=0; i<fileNames.size(); i++) {
       
   632                 int l = fileNames.at(i).length();
       
   633                 memcpy(f, fileNames.at(i).utf16(), l * sizeof(ushort));
       
   634                 f += l;
       
   635                 *f++ = 0;
       
   636             }
       
   637             *f = 0;
       
   638 
       
   639             return setData(result, pmedium);
       
   640         } else if (getCf(formatetc) == CF_INETURL_W) {
       
   641             QList<QUrl> urls = mimeData->urls();
       
   642             QByteArray result;
       
   643             QString url = urls.at(0).toString();
       
   644             result = QByteArray((const char *)url.utf16(), url.length() * sizeof(ushort));
       
   645             result.append('\0');
       
   646             result.append('\0');
       
   647             return setData(result, pmedium);
       
   648         } else if (getCf(formatetc) == CF_INETURL) {
       
   649             QList<QUrl> urls = mimeData->urls();
       
   650             QByteArray result = urls.at(0).toString().toLocal8Bit();
       
   651             return setData(result, pmedium);
       
   652         }
       
   653     }
       
   654 
       
   655     return false;
       
   656 }
       
   657 
       
   658 bool QWindowsMimeURI::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
       
   659 {
       
   660     return mimeType == QLatin1String("text/uri-list")
       
   661            && (canGetData(CF_HDROP, pDataObj) || canGetData(CF_INETURL_W, pDataObj) || canGetData(CF_INETURL, pDataObj));
       
   662 }
       
   663 
       
   664 QString QWindowsMimeURI::mimeForFormat(const FORMATETC &formatetc) const
       
   665 {
       
   666     QString format;
       
   667     if (getCf(formatetc) == CF_HDROP || getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL)
       
   668         format = QLatin1String("text/uri-list");
       
   669     return format;
       
   670 }
       
   671 
       
   672 QVector<FORMATETC> QWindowsMimeURI::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
       
   673 {
       
   674     QVector<FORMATETC> formatics;
       
   675     if (mimeType == QLatin1String("text/uri-list")) {
       
   676         if (canConvertFromMime(setCf(CF_HDROP), mimeData))
       
   677             formatics += setCf(CF_HDROP);
       
   678         if (canConvertFromMime(setCf(CF_INETURL_W), mimeData))
       
   679             formatics += setCf(CF_INETURL_W);
       
   680         if (canConvertFromMime(setCf(CF_INETURL), mimeData))
       
   681             formatics += setCf(CF_INETURL);
       
   682     }
       
   683     return formatics;
       
   684 }
       
   685 
       
   686 QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const
       
   687 {
       
   688     if (mimeType == QLatin1String("text/uri-list")) {
       
   689         if (canGetData(CF_HDROP, pDataObj)) {
       
   690             QByteArray texturi;
       
   691             QList<QVariant> urls;
       
   692 
       
   693             QByteArray data = getData(CF_HDROP, pDataObj);
       
   694             if (data.isEmpty())
       
   695                 return QVariant();
       
   696 
       
   697             LPDROPFILES hdrop = (LPDROPFILES)data.data();
       
   698             if (hdrop->fWide) {
       
   699                 const wchar_t* filesw = (const wchar_t *)(data.data() + hdrop->pFiles);
       
   700                 int i = 0;
       
   701                 while (filesw[i]) {
       
   702                     QString fileurl = QString::fromWCharArray(filesw + i);
       
   703                     urls += QUrl::fromLocalFile(fileurl);
       
   704                     i += fileurl.length()+1;
       
   705                 }
       
   706             } else {
       
   707                 const char* files = (const char *)data.data() + hdrop->pFiles;
       
   708                 int i=0;
       
   709                 while (files[i]) {
       
   710                     urls += QUrl::fromLocalFile(QString::fromLocal8Bit(files+i));
       
   711                     i += int(strlen(files+i))+1;
       
   712                 }
       
   713             }
       
   714 
       
   715             if (preferredType == QVariant::Url && urls.size() == 1)
       
   716                 return urls.at(0);
       
   717             else if (!urls.isEmpty())
       
   718                 return urls;
       
   719         } else if (canGetData(CF_INETURL_W, pDataObj)) {
       
   720             QByteArray data = getData(CF_INETURL_W, pDataObj);
       
   721             if (data.isEmpty())
       
   722                 return QVariant();
       
   723             return QUrl(QString::fromWCharArray((const wchar_t *)data.constData()));
       
   724          } else if (canGetData(CF_INETURL, pDataObj)) {
       
   725             QByteArray data = getData(CF_INETURL, pDataObj);
       
   726             if (data.isEmpty())
       
   727                 return QVariant();
       
   728             return QUrl(QString::fromLocal8Bit(data.constData()));
       
   729         }
       
   730     }
       
   731     return QVariant();
       
   732 }
       
   733 
       
   734 class QWindowsMimeHtml : public QWindowsMime
       
   735 {
       
   736 public:
       
   737     QWindowsMimeHtml();
       
   738 
       
   739     // for converting from Qt
       
   740     bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
       
   741     bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const;
       
   742     QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
       
   743 
       
   744     // for converting to Qt
       
   745     bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
       
   746     QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const;
       
   747     QString mimeForFormat(const FORMATETC &formatetc) const;
       
   748 
       
   749 private:
       
   750     int CF_HTML;
       
   751 };
       
   752 
       
   753 QWindowsMimeHtml::QWindowsMimeHtml()
       
   754 {
       
   755     CF_HTML = QWindowsMime::registerMimeType(QLatin1String("HTML Format"));
       
   756 }
       
   757 
       
   758 QVector<FORMATETC> QWindowsMimeHtml::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
       
   759 {
       
   760     QVector<FORMATETC> formatetcs;
       
   761     if (mimeType == QLatin1String("text/html") && (!mimeData->html().isEmpty()))
       
   762         formatetcs += setCf(CF_HTML);
       
   763     return formatetcs;
       
   764 }
       
   765 
       
   766 QString QWindowsMimeHtml::mimeForFormat(const FORMATETC &formatetc) const
       
   767 {
       
   768     if (getCf(formatetc) == CF_HTML)
       
   769         return QLatin1String("text/html");
       
   770     return QString();
       
   771 }
       
   772 
       
   773 bool QWindowsMimeHtml::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
       
   774 {
       
   775     return mimeType == QLatin1String("text/html") && canGetData(CF_HTML, pDataObj);
       
   776 }
       
   777 
       
   778 
       
   779 bool QWindowsMimeHtml::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
       
   780 {
       
   781     return getCf(formatetc) == CF_HTML && (!mimeData->html().isEmpty());
       
   782 }
       
   783 
       
   784 /*
       
   785 The windows HTML clipboard format is as follows (xxxxxxxxxx is a 10 integer number giving the positions
       
   786 in bytes). Charset used is mostly utf8, but can be different, ie. we have to look for the <meta> charset tag
       
   787 
       
   788   Version: 1.0
       
   789   StartHTML:xxxxxxxxxx
       
   790   EndHTML:xxxxxxxxxx
       
   791   StartFragment:xxxxxxxxxx
       
   792   EndFragment:xxxxxxxxxx
       
   793   ...html...
       
   794 
       
   795 */
       
   796 QVariant QWindowsMimeHtml::convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const
       
   797 {
       
   798     Q_UNUSED(preferredType);
       
   799     QVariant result;
       
   800     if (canConvertToMime(mime, pDataObj)) {
       
   801         QByteArray html = getData(CF_HTML, pDataObj);
       
   802 #ifdef QMIME_DEBUG
       
   803         qDebug("QWindowsMimeHtml::convertToMime");
       
   804         qDebug("raw :");
       
   805         qDebug(html);
       
   806 #endif
       
   807         int start = html.indexOf("StartFragment:");
       
   808         int end = html.indexOf("EndFragment:");
       
   809 
       
   810         if (start != -1) {
       
   811             int startOffset = start + 14;
       
   812             int i = startOffset;
       
   813             while (html.at(i) != '\r' && html.at(i) != '\n')
       
   814                 ++i;
       
   815             QByteArray bytecount = html.mid(startOffset, i - startOffset);
       
   816             start = bytecount.toInt();
       
   817         }
       
   818 
       
   819         if (end != -1) {
       
   820             int endOffset = end + 12;
       
   821             int i = endOffset ;
       
   822             while (html.at(i) != '\r' && html.at(i) != '\n')
       
   823                 ++i;
       
   824             QByteArray bytecount = html.mid(endOffset , i - endOffset);
       
   825             end = bytecount.toInt();
       
   826         }
       
   827 
       
   828         if (end > start && start > 0) {
       
   829             html = "<!--StartFragment-->" + html.mid(start, end - start);
       
   830             html += "<!--EndFragment-->";
       
   831             html.replace('\r', "");
       
   832             result = QString::fromUtf8(html);
       
   833         }
       
   834     }
       
   835     return result;
       
   836 }
       
   837 
       
   838 bool QWindowsMimeHtml::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
       
   839 {
       
   840     if (canConvertFromMime(formatetc, mimeData)) {
       
   841         QByteArray data = mimeData->html().toUtf8();
       
   842         QByteArray result =
       
   843             "Version:1.0\r\n"                    // 0-12
       
   844             "StartHTML:0000000105\r\n"            // 13-35
       
   845             "EndHTML:0000000000\r\n"            // 36-55
       
   846             "StartFragment:0000000000\r\n"            // 58-86
       
   847             "EndFragment:0000000000\r\n\r\n";   // 87-105
       
   848 
       
   849         if (data.indexOf("<!--StartFragment-->") == -1)
       
   850             result += "<!--StartFragment-->";
       
   851         result += data;
       
   852         if (data.indexOf("<!--EndFragment-->") == -1)
       
   853             result += "<!--EndFragment-->";
       
   854 
       
   855         // set the correct number for EndHTML
       
   856         QByteArray pos = QString::number(result.size()).toLatin1();
       
   857         memcpy((char *)(result.data() + 53 - pos.length()), pos.constData(), pos.length());
       
   858 
       
   859         // set correct numbers for StartFragment and EndFragment
       
   860         pos = QString::number(result.indexOf("<!--StartFragment-->") + 20).toLatin1();
       
   861         memcpy((char *)(result.data() + 79 - pos.length()), pos.constData(), pos.length());
       
   862         pos = QString::number(result.indexOf("<!--EndFragment-->")).toLatin1();
       
   863         memcpy((char *)(result.data() + 103 - pos.length()), pos.constData(), pos.length());
       
   864 
       
   865         return setData(result, pmedium);
       
   866     }
       
   867     return false;
       
   868 }
       
   869 
       
   870 
       
   871 #ifndef QT_NO_IMAGEFORMAT_BMP
       
   872 class QWindowsMimeImage : public QWindowsMime
       
   873 {
       
   874 public:
       
   875     QWindowsMimeImage();
       
   876     // for converting from Qt
       
   877     bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
       
   878     bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const;
       
   879     QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
       
   880 
       
   881     // for converting to Qt
       
   882     bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
       
   883     QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const;
       
   884     QString mimeForFormat(const FORMATETC &formatetc) const;
       
   885 private:
       
   886     bool hasOriginalDIBV5(IDataObject *pDataObj) const;
       
   887     UINT CF_PNG;
       
   888 };
       
   889 
       
   890 QWindowsMimeImage::QWindowsMimeImage()
       
   891 {
       
   892     CF_PNG = RegisterClipboardFormat(L"PNG");
       
   893 }
       
   894 
       
   895 QVector<FORMATETC> QWindowsMimeImage::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
       
   896 {
       
   897     QVector<FORMATETC> formatetcs;
       
   898     if (mimeData->hasImage() && mimeType == QLatin1String("application/x-qt-image")) {
       
   899         //add DIBV5 if image has alpha channel
       
   900         QImage image = qvariant_cast<QImage>(mimeData->imageData());
       
   901         if (!image.isNull() && image.hasAlphaChannel())
       
   902             formatetcs += setCf(CF_DIBV5);
       
   903         formatetcs += setCf(CF_DIB);
       
   904     }
       
   905     return formatetcs;
       
   906 }
       
   907 
       
   908 QString QWindowsMimeImage::mimeForFormat(const FORMATETC &formatetc) const
       
   909 {
       
   910     int cf = getCf(formatetc);
       
   911     if (cf == CF_DIB || cf == CF_DIBV5 || cf == int(CF_PNG))
       
   912        return QLatin1String("application/x-qt-image");
       
   913     return QString();
       
   914 }
       
   915 
       
   916 bool QWindowsMimeImage::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
       
   917 {
       
   918     if ((mimeType == QLatin1String("application/x-qt-image")) &&
       
   919         (canGetData(CF_DIB, pDataObj) || canGetData(CF_PNG, pDataObj)))
       
   920         return true;
       
   921     return false;
       
   922 }
       
   923 
       
   924 bool QWindowsMimeImage::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
       
   925 {
       
   926     int cf = getCf(formatetc);
       
   927     if (mimeData->hasImage()) {
       
   928         if (cf == CF_DIB)
       
   929             return true;
       
   930         else if (cf == CF_DIBV5) {
       
   931             //support DIBV5 conversion only if the image has alpha channel
       
   932             QImage image = qvariant_cast<QImage>(mimeData->imageData());
       
   933             if (!image.isNull() && image.hasAlphaChannel())
       
   934                 return true;
       
   935         }
       
   936     }
       
   937     return false;
       
   938 }
       
   939 
       
   940 bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
       
   941 {
       
   942     int cf = getCf(formatetc);
       
   943     if ((cf == CF_DIB || cf == CF_DIBV5) && mimeData->hasImage()) {
       
   944         QImage img = qvariant_cast<QImage>(mimeData->imageData());
       
   945         if (img.isNull())
       
   946             return false;
       
   947         QByteArray ba;
       
   948         QDataStream s(&ba, QIODevice::WriteOnly);
       
   949         s.setByteOrder(QDataStream::LittleEndian);// Intel byte order ####
       
   950         if (cf == CF_DIB) {
       
   951             if (qt_write_dib(s, img))
       
   952                 return setData(ba, pmedium);
       
   953         } else {
       
   954             if (qt_write_dibv5(s, img))
       
   955                 return setData(ba, pmedium);
       
   956         }
       
   957     }
       
   958     return false;
       
   959 }
       
   960 
       
   961 bool QWindowsMimeImage::hasOriginalDIBV5(IDataObject *pDataObj) const
       
   962 {
       
   963     bool isSynthesized = true;
       
   964     IEnumFORMATETC *pEnum =NULL;
       
   965     HRESULT res = pDataObj->EnumFormatEtc(1, &pEnum);
       
   966     if (res == S_OK && pEnum) {
       
   967         FORMATETC fc;
       
   968         while ((res = pEnum->Next(1, &fc, 0)) == S_OK) {
       
   969             if (fc.ptd)
       
   970                 CoTaskMemFree(fc.ptd);
       
   971             if (fc.cfFormat == CF_DIB)
       
   972                 break;
       
   973             else if (fc.cfFormat == CF_DIBV5) {
       
   974                 isSynthesized  = false;
       
   975                 break;
       
   976             }
       
   977         }
       
   978         pEnum->Release();
       
   979     }
       
   980     return !isSynthesized;
       
   981 }
       
   982 
       
   983 QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const
       
   984 {
       
   985     Q_UNUSED(preferredType);
       
   986     QVariant result;
       
   987     if (mimeType != QLatin1String("application/x-qt-image"))
       
   988         return result;
       
   989     //Try to convert from a format which has more data
       
   990     //DIBV5, use only if its is not synthesized
       
   991     if (canGetData(CF_DIBV5, pDataObj) && hasOriginalDIBV5(pDataObj)) {
       
   992         QImage img;
       
   993         QByteArray data = getData(CF_DIBV5, pDataObj);
       
   994         QDataStream s(&data, QIODevice::ReadOnly);
       
   995         s.setByteOrder(QDataStream::LittleEndian);
       
   996         if (qt_read_dibv5(s, img)) { // #### supports only 32bit DIBV5
       
   997             return img;
       
   998         }
       
   999     }
       
  1000     //PNG, MS Office place this (undocumented)
       
  1001     if (canGetData(CF_PNG, pDataObj)) {
       
  1002         QImage img;
       
  1003         QByteArray data = getData(CF_PNG, pDataObj);
       
  1004         if (img.loadFromData(data, "PNG")) {
       
  1005             return img;
       
  1006         }
       
  1007     }
       
  1008     //Fallback to DIB
       
  1009     if (canGetData(CF_DIB, pDataObj)) {
       
  1010         QImage img;
       
  1011         QByteArray data = getData(CF_DIB, pDataObj);
       
  1012         QDataStream s(&data, QIODevice::ReadOnly);
       
  1013         s.setByteOrder(QDataStream::LittleEndian);// Intel byte order ####
       
  1014         if (qt_read_dib(s, img)) { // ##### encaps "-14"
       
  1015             return img;
       
  1016         }
       
  1017     }
       
  1018     // Failed
       
  1019     return result;
       
  1020 }
       
  1021 #endif
       
  1022 
       
  1023 class QBuiltInMimes : public QWindowsMime
       
  1024 {
       
  1025 public:
       
  1026     QBuiltInMimes();
       
  1027 
       
  1028     // for converting from Qt
       
  1029     bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
       
  1030     bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const;
       
  1031     QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
       
  1032 
       
  1033     // for converting to Qt
       
  1034     bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
       
  1035     QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const;
       
  1036     QString mimeForFormat(const FORMATETC &formatetc) const;
       
  1037 
       
  1038 private:
       
  1039     QMap<int, QString> outFormats;
       
  1040     QMap<int, QString> inFormats;
       
  1041 };
       
  1042 
       
  1043 QBuiltInMimes::QBuiltInMimes()
       
  1044 : QWindowsMime()
       
  1045 {
       
  1046     outFormats.insert(QWindowsMime::registerMimeType(QLatin1String("application/x-color")), QLatin1String("application/x-color"));
       
  1047     inFormats.insert(QWindowsMime::registerMimeType(QLatin1String("application/x-color")), QLatin1String("application/x-color"));
       
  1048 }
       
  1049 
       
  1050 bool QBuiltInMimes::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
       
  1051 {
       
  1052     // really check
       
  1053     return formatetc.tymed & TYMED_HGLOBAL
       
  1054         && outFormats.contains(formatetc.cfFormat)
       
  1055         && mimeData->formats().contains(outFormats.value(formatetc.cfFormat));
       
  1056 }
       
  1057 
       
  1058 bool QBuiltInMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
       
  1059 {
       
  1060     if (canConvertFromMime(formatetc, mimeData)) {
       
  1061         QByteArray data;
       
  1062         if (outFormats.value(getCf(formatetc)) == QLatin1String("text/html")) {
       
  1063             // text/html is in wide chars on windows (compatible with mozillia)
       
  1064             QString html = mimeData->html();
       
  1065             // same code as in the text converter up above
       
  1066             const QChar *u = html.unicode();
       
  1067             QString res;
       
  1068             const int s = html.length();
       
  1069             int maxsize = s + s/40 + 3;
       
  1070             res.resize(maxsize);
       
  1071             int ri = 0;
       
  1072             bool cr = false;
       
  1073             for (int i=0; i < s; ++i) {
       
  1074                 if (*u == QLatin1Char('\r'))
       
  1075                     cr = true;
       
  1076                 else {
       
  1077                     if (*u == QLatin1Char('\n') && !cr)
       
  1078                         res[ri++] = QLatin1Char('\r');
       
  1079                     cr = false;
       
  1080                 }
       
  1081                 res[ri++] = *u;
       
  1082                 if (ri+3 >= maxsize) {
       
  1083                     maxsize += maxsize/4;
       
  1084                     res.resize(maxsize);
       
  1085                 }
       
  1086                 ++u;
       
  1087             }
       
  1088             res.truncate(ri);
       
  1089             const int byteLength = res.length() * sizeof(ushort);
       
  1090             QByteArray r(byteLength + 2, '\0');
       
  1091             memcpy(r.data(), res.unicode(), byteLength);
       
  1092             r[byteLength] = 0;
       
  1093             r[byteLength+1] = 0;
       
  1094             data = r;
       
  1095         } else {
       
  1096 #ifndef QT_NO_DRAGANDDROP
       
  1097             data = QInternalMimeData::renderDataHelper(outFormats.value(getCf(formatetc)), mimeData);
       
  1098 #endif //QT_NO_DRAGANDDROP
       
  1099         }
       
  1100         return setData(data, pmedium);
       
  1101     }
       
  1102     return false;
       
  1103 }
       
  1104 
       
  1105 QVector<FORMATETC> QBuiltInMimes::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
       
  1106 {
       
  1107     QVector<FORMATETC> formatetcs;
       
  1108     if (!outFormats.keys(mimeType).isEmpty() && mimeData->formats().contains(mimeType))
       
  1109         formatetcs += setCf(outFormats.key(mimeType));
       
  1110     return formatetcs;
       
  1111 }
       
  1112 
       
  1113 bool QBuiltInMimes::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
       
  1114 {
       
  1115     return (!inFormats.keys(mimeType).isEmpty())
       
  1116         && canGetData(inFormats.key(mimeType), pDataObj);
       
  1117 }
       
  1118 
       
  1119 QVariant QBuiltInMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const
       
  1120 {
       
  1121     QVariant val;
       
  1122     if (canConvertToMime(mimeType, pDataObj)) {
       
  1123         QByteArray data = getData(inFormats.key(mimeType), pDataObj);
       
  1124         if (!data.isEmpty()) {
       
  1125 #ifdef QMIME_DEBUG
       
  1126             qDebug("QBuiltInMimes::convertToMime()");
       
  1127 #endif
       
  1128             if (mimeType == QLatin1String("text/html") && preferredType == QVariant::String) {
       
  1129                 // text/html is in wide chars on windows (compatible with Mozilla)
       
  1130                 val = QString::fromWCharArray((const wchar_t *)data.data());
       
  1131             } else {
       
  1132                 val = data; // it should be enough to return the data and let QMimeData do the rest.
       
  1133             }
       
  1134         }
       
  1135     }
       
  1136     return val;
       
  1137 }
       
  1138 
       
  1139 QString QBuiltInMimes::mimeForFormat(const FORMATETC &formatetc) const
       
  1140 {
       
  1141     return inFormats.value(getCf(formatetc));
       
  1142 }
       
  1143 
       
  1144 
       
  1145 class QLastResortMimes : public QWindowsMime
       
  1146 {
       
  1147 public:
       
  1148 
       
  1149     QLastResortMimes();
       
  1150     // for converting from Qt
       
  1151     bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
       
  1152     bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const;
       
  1153     QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
       
  1154 
       
  1155     // for converting to Qt
       
  1156     bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
       
  1157     QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const;
       
  1158     QString mimeForFormat(const FORMATETC &formatetc) const;
       
  1159 
       
  1160 private:
       
  1161     QMap<int, QString> formats;
       
  1162     static QStringList ianaTypes;
       
  1163     static QStringList excludeList;
       
  1164 };
       
  1165 
       
  1166 QStringList QLastResortMimes::ianaTypes;
       
  1167 QStringList QLastResortMimes::excludeList;
       
  1168 
       
  1169 QLastResortMimes::QLastResortMimes()
       
  1170 {
       
  1171     //MIME Media-Types
       
  1172     if (!ianaTypes.size()) {
       
  1173         ianaTypes.append(QLatin1String("application/"));
       
  1174         ianaTypes.append(QLatin1String("audio/"));
       
  1175         ianaTypes.append(QLatin1String("example/"));
       
  1176         ianaTypes.append(QLatin1String("image/"));
       
  1177         ianaTypes.append(QLatin1String("message/"));
       
  1178         ianaTypes.append(QLatin1String("model/"));
       
  1179         ianaTypes.append(QLatin1String("multipart/"));
       
  1180         ianaTypes.append(QLatin1String("text/"));
       
  1181         ianaTypes.append(QLatin1String("video/"));
       
  1182     }
       
  1183     //Types handled by other classes
       
  1184     if (!excludeList.size()) {
       
  1185         excludeList.append(QLatin1String("HTML Format"));
       
  1186         excludeList.append(QLatin1String("UniformResourceLocator"));
       
  1187         excludeList.append(QLatin1String("text/html"));
       
  1188         excludeList.append(QLatin1String("text/plain"));
       
  1189         excludeList.append(QLatin1String("text/uri-list"));
       
  1190         excludeList.append(QLatin1String("application/x-qt-image"));
       
  1191         excludeList.append(QLatin1String("application/x-color"));
       
  1192     }
       
  1193 }
       
  1194 
       
  1195 bool QLastResortMimes::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
       
  1196 {
       
  1197     // really check
       
  1198 #ifndef QT_NO_DRAGANDDROP
       
  1199     return formatetc.tymed & TYMED_HGLOBAL
       
  1200         && (formats.contains(formatetc.cfFormat)
       
  1201         && QInternalMimeData::hasFormatHelper(formats.value(formatetc.cfFormat), mimeData));
       
  1202 #else
       
  1203     Q_UNUSED(mimeData);
       
  1204     Q_UNUSED(formatetc);
       
  1205     return formatetc.tymed & TYMED_HGLOBAL
       
  1206         && formats.contains(formatetc.cfFormat);
       
  1207 #endif //QT_NO_DRAGANDDROP
       
  1208 }
       
  1209 
       
  1210 bool QLastResortMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
       
  1211 {
       
  1212 #ifndef QT_NO_DRAGANDDROP
       
  1213     return canConvertFromMime(formatetc, mimeData)
       
  1214         && setData(QInternalMimeData::renderDataHelper(formats.value(getCf(formatetc)), mimeData), pmedium);
       
  1215 #else
       
  1216     Q_UNUSED(mimeData);
       
  1217     Q_UNUSED(formatetc);
       
  1218     Q_UNUSED(pmedium);
       
  1219     return false;
       
  1220 #endif //QT_NO_DRAGANDDROP
       
  1221 }
       
  1222 
       
  1223 QVector<FORMATETC> QLastResortMimes::formatsForMime(const QString &mimeType, const QMimeData * /*mimeData*/) const
       
  1224 {
       
  1225     QVector<FORMATETC> formatetcs;
       
  1226     if (!formats.keys(mimeType).isEmpty()) {
       
  1227         formatetcs += setCf(formats.key(mimeType));
       
  1228     } else if (!excludeList.contains(mimeType, Qt::CaseInsensitive)){
       
  1229         // register any other available formats
       
  1230         int cf = QWindowsMime::registerMimeType(mimeType);
       
  1231         QLastResortMimes *that = const_cast<QLastResortMimes *>(this);
       
  1232         that->formats.insert(cf, mimeType);
       
  1233         formatetcs += setCf(cf);
       
  1234     }
       
  1235     return formatetcs;
       
  1236 }
       
  1237 static const char x_qt_windows_mime[] = "application/x-qt-windows-mime;value=\"";
       
  1238 
       
  1239 static bool isCustomMimeType(const QString &mimeType)
       
  1240 {
       
  1241     return mimeType.startsWith(QLatin1String(x_qt_windows_mime), Qt::CaseInsensitive);
       
  1242 }
       
  1243 
       
  1244 static QString customMimeType(const QString &mimeType)
       
  1245 {
       
  1246     int len = sizeof(x_qt_windows_mime) - 1;
       
  1247     int n = mimeType.lastIndexOf(QLatin1Char('\"'))-len;
       
  1248     return mimeType.mid(len, n);
       
  1249 }
       
  1250 
       
  1251 bool QLastResortMimes::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
       
  1252 {
       
  1253     if (isCustomMimeType(mimeType)) {
       
  1254         QString clipFormat = customMimeType(mimeType);
       
  1255         int cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16()));
       
  1256         return canGetData(cf, pDataObj);
       
  1257     } else if (formats.keys(mimeType).isEmpty()) {
       
  1258         // if it is not in there then register it an see if we can get it
       
  1259         int cf = QWindowsMime::registerMimeType(mimeType);
       
  1260         return canGetData(cf, pDataObj);
       
  1261     } else {
       
  1262         return canGetData(formats.key(mimeType), pDataObj);
       
  1263     }
       
  1264     return false;
       
  1265 }
       
  1266 
       
  1267 QVariant QLastResortMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const
       
  1268 {
       
  1269     Q_UNUSED(preferredType);
       
  1270     QVariant val;
       
  1271     if (canConvertToMime(mimeType, pDataObj)) {
       
  1272         QByteArray data;
       
  1273         if (isCustomMimeType(mimeType)) {
       
  1274             QString clipFormat = customMimeType(mimeType);
       
  1275             int cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16()));
       
  1276             data = getData(cf, pDataObj);
       
  1277         } else if (formats.keys(mimeType).isEmpty()) {
       
  1278             int cf = QWindowsMime::registerMimeType(mimeType);
       
  1279             data = getData(cf, pDataObj);
       
  1280         } else {
       
  1281             data = getData(formats.key(mimeType), pDataObj);
       
  1282         }
       
  1283         if (!data.isEmpty())
       
  1284             val = data; // it should be enough to return the data and let QMimeData do the rest.
       
  1285     }
       
  1286     return val;
       
  1287 }
       
  1288 
       
  1289 QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const
       
  1290 {
       
  1291     QString format = formats.value(getCf(formatetc));
       
  1292     if (!format.isEmpty())
       
  1293         return format;
       
  1294 
       
  1295     wchar_t buffer[256];
       
  1296     int len = GetClipboardFormatName(getCf(formatetc), buffer, 256);
       
  1297 
       
  1298     if (len) {
       
  1299         QString clipFormat = QString::fromWCharArray(buffer, len);
       
  1300 #ifndef QT_NO_DRAGANDDROP
       
  1301         if (QInternalMimeData::canReadData(clipFormat))
       
  1302             format = clipFormat;
       
  1303         else if((formatetc.cfFormat >= 0xC000)){
       
  1304             //create the mime as custom. not registered.
       
  1305             if (!excludeList.contains(clipFormat, Qt::CaseInsensitive)) {
       
  1306                 //check if this is a mime type
       
  1307                 bool ianaType = false;
       
  1308                 int sz = ianaTypes.size();
       
  1309                 for (int i = 0; i < sz; i++) {
       
  1310                     if (clipFormat.startsWith(ianaTypes[i], Qt::CaseInsensitive)) {
       
  1311                         ianaType =  true;
       
  1312                         break;
       
  1313                     }
       
  1314                 }
       
  1315                 if (!ianaType)
       
  1316                     format = QLatin1String(x_qt_windows_mime) + clipFormat + QLatin1Char('\"');
       
  1317                 else
       
  1318                     format = clipFormat;
       
  1319             }
       
  1320         }
       
  1321 #endif //QT_NO_DRAGANDDROP
       
  1322     }
       
  1323 
       
  1324     return format;
       
  1325 }
       
  1326 
       
  1327 QWindowsMimeList::QWindowsMimeList()
       
  1328     : initialized(false)
       
  1329 {
       
  1330 }
       
  1331 
       
  1332 QWindowsMimeList::~QWindowsMimeList()
       
  1333 {
       
  1334     while (mimes.size())
       
  1335         delete mimes.first();
       
  1336 }
       
  1337 
       
  1338 
       
  1339 void QWindowsMimeList::init()
       
  1340 {
       
  1341     if (!initialized) {
       
  1342         initialized = true;
       
  1343 #ifndef QT_NO_IMAGEFORMAT_BMP
       
  1344         new QWindowsMimeImage;
       
  1345 #endif
       
  1346         new QLastResortMimes;
       
  1347         new QWindowsMimeText;
       
  1348         new QWindowsMimeURI;
       
  1349 
       
  1350         new QWindowsMimeHtml;
       
  1351         new QBuiltInMimes;
       
  1352     }
       
  1353 }
       
  1354 
       
  1355 void QWindowsMimeList::addWindowsMime(QWindowsMime * mime)
       
  1356 {
       
  1357     init();
       
  1358     mimes.append(mime);
       
  1359 }
       
  1360 
       
  1361 void QWindowsMimeList::removeWindowsMime(QWindowsMime * mime)
       
  1362 {
       
  1363     init();
       
  1364     mimes.removeAll(mime);
       
  1365 }
       
  1366 
       
  1367 QList<QWindowsMime*> QWindowsMimeList::windowsMimes()
       
  1368 {
       
  1369     init();
       
  1370     return mimes;
       
  1371 }
       
  1372 
       
  1373 #ifndef QT_NO_IMAGEFORMAT_BMP
       
  1374 static bool qt_write_dibv5(QDataStream &s, QImage image)
       
  1375 {
       
  1376     QIODevice* d = s.device();
       
  1377     if (!d->isWritable())
       
  1378         return false;
       
  1379 
       
  1380     //depth will be always 32
       
  1381     int bpl_bmp = image.width()*4;
       
  1382 
       
  1383     BMP_BITMAPV5HEADER bi ={0};
       
  1384     bi.bV5Size          = sizeof(BMP_BITMAPV5HEADER);
       
  1385     bi.bV5Width         = image.width();
       
  1386     bi.bV5Height        = image.height();
       
  1387     bi.bV5Planes        = 1;
       
  1388     bi.bV5BitCount      = 32;
       
  1389     bi.bV5Compression   = BI_BITFIELDS;
       
  1390     bi.bV5SizeImage     = bpl_bmp*image.height();
       
  1391     bi.bV5XPelsPerMeter = 0;
       
  1392     bi.bV5YPelsPerMeter = 0;
       
  1393     bi.bV5ClrUsed       = 0;
       
  1394     bi.bV5ClrImportant  = 0;
       
  1395     bi.bV5BlueMask      = 0x000000ff;
       
  1396     bi.bV5GreenMask     = 0x0000ff00;
       
  1397     bi.bV5RedMask       = 0x00ff0000;
       
  1398     bi.bV5AlphaMask     = 0xff000000;
       
  1399     bi.bV5CSType        = BMP_LCS_sRGB;         //LCS_sRGB
       
  1400     bi.bV5Intent        = BMP_LCS_GM_IMAGES;    //LCS_GM_IMAGES
       
  1401 
       
  1402     d->write(reinterpret_cast<const char*>(&bi), bi.bV5Size);
       
  1403     if (s.status() != QDataStream::Ok)
       
  1404         return false;
       
  1405 
       
  1406     DWORD colorSpace[3] = {0x00ff0000,0x0000ff00,0x000000ff};
       
  1407     d->write(reinterpret_cast<const char*>(colorSpace), sizeof(colorSpace));
       
  1408     if (s.status() != QDataStream::Ok)
       
  1409         return false;
       
  1410 
       
  1411     if (image.format() != QImage::Format_ARGB32)
       
  1412         image = image.convertToFormat(QImage::Format_ARGB32);
       
  1413 
       
  1414     uchar *buf = new uchar[bpl_bmp];
       
  1415     uchar *b;
       
  1416 
       
  1417     memset(buf, 0, bpl_bmp);
       
  1418     for (int y=image.height()-1; y>=0; y--) {
       
  1419         // write the image bits
       
  1420         QRgb *p = (QRgb *)image.scanLine(y);
       
  1421         QRgb *end = p + image.width();
       
  1422         b = buf;
       
  1423         while (p < end) {
       
  1424             int alpha = qAlpha(*p);
       
  1425             if (alpha) {
       
  1426                 *b++ = qBlue(*p);
       
  1427                 *b++ = qGreen(*p);
       
  1428                 *b++ = qRed(*p);
       
  1429             } else {
       
  1430                 //white for fully transparent pixels.
       
  1431                 *b++ = 0xff;
       
  1432                 *b++ = 0xff;
       
  1433                 *b++ = 0xff;
       
  1434             }
       
  1435             *b++ = alpha;
       
  1436             p++;
       
  1437         }
       
  1438         d->write((char*)buf, bpl_bmp);
       
  1439         if (s.status() != QDataStream::Ok) {
       
  1440             delete[] buf;
       
  1441             return false;
       
  1442         }
       
  1443     }
       
  1444     delete[] buf;
       
  1445     return true;
       
  1446 }
       
  1447 
       
  1448 static int calc_shift(int mask)
       
  1449 {
       
  1450     int result = 0;
       
  1451     while (!(mask & 1)) {
       
  1452         result++;
       
  1453         mask >>= 1;
       
  1454     }
       
  1455     return result;
       
  1456 }
       
  1457 
       
  1458 //Supports only 32 bit DIBV5
       
  1459 static bool qt_read_dibv5(QDataStream &s, QImage &image)
       
  1460 {
       
  1461     BMP_BITMAPV5HEADER bi;
       
  1462     QIODevice* d = s.device();
       
  1463     if (d->atEnd())
       
  1464         return false;
       
  1465 
       
  1466     d->read((char *)&bi, sizeof(bi));   // read BITMAPV5HEADER header
       
  1467     if (s.status() != QDataStream::Ok)
       
  1468         return false;
       
  1469 
       
  1470     int nbits = bi.bV5BitCount;
       
  1471     int comp = bi.bV5Compression;
       
  1472     if (nbits != 32 || bi.bV5Planes != 1 || comp != BMP_BITFIELDS)
       
  1473         return false; //Unsupported DIBV5 format
       
  1474 
       
  1475     int w = bi.bV5Width, h = bi.bV5Height;
       
  1476     int red_mask = bi.bV5RedMask;
       
  1477     int green_mask = bi.bV5GreenMask;
       
  1478     int blue_mask = bi.bV5BlueMask;
       
  1479     int alpha_mask = bi.bV5AlphaMask;
       
  1480     int red_shift = 0;
       
  1481     int green_shift = 0;
       
  1482     int blue_shift = 0;
       
  1483     int alpha_shift = 0;
       
  1484     QImage::Format format = QImage::Format_ARGB32;
       
  1485 
       
  1486     if (bi.bV5Height < 0)
       
  1487         h = -h;     // support images with negative height
       
  1488     if (image.size() != QSize(w, h) || image.format() != format) {
       
  1489         image = QImage(w, h, format);
       
  1490         if (image.isNull())     // could not create image
       
  1491             return false;
       
  1492     }
       
  1493     image.setDotsPerMeterX(bi.bV5XPelsPerMeter);
       
  1494     image.setDotsPerMeterY(bi.bV5YPelsPerMeter);
       
  1495     // read color table
       
  1496     DWORD colorSpace[3];
       
  1497     if (d->read((char *)colorSpace, sizeof(colorSpace)) != sizeof(colorSpace))
       
  1498         return false;
       
  1499 
       
  1500     red_shift = calc_shift(red_mask);
       
  1501     green_shift = calc_shift(green_mask);
       
  1502     blue_shift = calc_shift(blue_mask);
       
  1503     if (alpha_mask) {
       
  1504         alpha_shift = calc_shift(alpha_mask);
       
  1505     }
       
  1506 
       
  1507     int  bpl = image.bytesPerLine();
       
  1508     uchar *data = image.bits();
       
  1509     register QRgb *p;
       
  1510     QRgb  *end;
       
  1511     uchar *buf24 = new uchar[bpl];
       
  1512     int    bpl24 = ((w*nbits+31)/32)*4;
       
  1513     uchar *b;
       
  1514     unsigned int c;
       
  1515 
       
  1516     while (--h >= 0) {
       
  1517         p = (QRgb *)(data + h*bpl);
       
  1518         end = p + w;
       
  1519         if (d->read((char *)buf24,bpl24) != bpl24)
       
  1520             break;
       
  1521         b = buf24;
       
  1522         while (p < end) {
       
  1523             c = *b | (*(b+1))<<8 | (*(b+2))<<16 | (*(b+3))<<24;
       
  1524             *p++ = qRgba(((c & red_mask) >> red_shift) ,
       
  1525                                     ((c & green_mask) >> green_shift),
       
  1526                                     ((c & blue_mask) >> blue_shift),
       
  1527                                     ((c & alpha_mask) >> alpha_shift));
       
  1528             b += 4;
       
  1529         }
       
  1530     }
       
  1531     delete[] buf24;
       
  1532 
       
  1533     if (bi.bV5Height < 0) {
       
  1534         // Flip the image
       
  1535         uchar *buf = new uchar[bpl];
       
  1536         h = -bi.bV5Height;
       
  1537         for (int y = 0; y < h/2; ++y) {
       
  1538             memcpy(buf, data + y*bpl, bpl);
       
  1539             memcpy(data + y*bpl, data + (h-y-1)*bpl, bpl);
       
  1540             memcpy(data + (h-y-1)*bpl, buf, bpl);
       
  1541         }
       
  1542         delete [] buf;
       
  1543     }
       
  1544 
       
  1545     return true;
       
  1546 }
       
  1547 
       
  1548 #endif
       
  1549 
       
  1550 QT_END_NAMESPACE