1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qmime.h"
43 
44 //#define USE_INTERNET_CONFIG
45 
46 #ifndef USE_INTERNET_CONFIG
47 # include "qfile.h"
48 # include "qfileinfo.h"
49 # include "qtextstream.h"
50 # include "qdir.h"
51 # include <unistd.h>
52 # include <sys/types.h>
53 # include <sys/stat.h>
54 # include <sys/fcntl.h>
55 #endif
56 
57 #include "qdebug.h"
58 #include "qpixmap.h"
59 #include "qimagewriter.h"
60 #include "qimagereader.h"
61 #include "qdatastream.h"
62 #include "qbuffer.h"
63 #include "qdatetime.h"
64 #include "qapplication_p.h"
65 #include "qtextcodec.h"
66 #include "qregexp.h"
67 #include "qurl.h"
68 #include "qmap.h"
69 #include <private/qt_mac_p.h>
70 
71 
72 #ifdef Q_WS_MAC32
73 #include <QuickTime/QuickTime.h>
74 #include <qlibrary.h>
75 #endif
76 
77 QT_BEGIN_NAMESPACE
78 
79 extern CGImageRef qt_mac_createCGImageFromQImage(const QImage &img, const QImage **imagePtr = 0); // qpaintengine_mac.cpp
80 
81 typedef QList<QMacPasteboardMime*> MimeList;
Q_GLOBAL_STATIC(MimeList,globalMimeList)82 Q_GLOBAL_STATIC(MimeList, globalMimeList)
83 
84 static void cleanup_mimes()
85 {
86     MimeList *mimes = globalMimeList();
87     while (!mimes->isEmpty())
88         delete mimes->takeFirst();
89 }
90 
Q_GLOBAL_STATIC(QStringList,globalDraggedTypesList)91 Q_GLOBAL_STATIC(QStringList, globalDraggedTypesList)
92 
93 /*!
94     \fn void qRegisterDraggedTypes(const QStringList &types)
95     \relates QMacPasteboardMime
96 
97     Registers the given \a types as custom pasteboard types.
98 
99     This function should be called to enable the Drag and Drop events
100     for custom pasteboard types on Cocoa implementations. This is required
101     in addition to a QMacPasteboardMime subclass implementation. By default
102     drag and drop is enabled for all standard pasteboard types.
103 
104    \sa QMacPasteboardMime
105 */
106 Q_GUI_EXPORT void qRegisterDraggedTypes(const QStringList &types)
107 {
108     (*globalDraggedTypesList()) += types;
109 }
110 
qEnabledDraggedTypes()111 const QStringList& qEnabledDraggedTypes()
112 {
113     return (*globalDraggedTypesList());
114 }
115 
116 
117 /*****************************************************************************
118   QDnD debug facilities
119  *****************************************************************************/
120 //#define DEBUG_MIME_MAPS
121 
122 ScrapFlavorType qt_mac_mime_type = 'CUTE';
123 CFStringRef qt_mac_mime_typeUTI = CFSTR("com.pasteboard.trolltech.marker");
124 
125 /*!
126   \class QMacPasteboardMime
127   \brief The QMacPasteboardMime class converts between a MIME type and a
128   \l{http://developer.apple.com/macosx/uniformtypeidentifiers.html}{Uniform
129   Type Identifier (UTI)} format.
130   \since 4.2
131 
132   \ingroup draganddrop
133 
134   Qt's drag and drop and clipboard facilities use the MIME
135   standard. On X11, this maps trivially to the Xdnd protocol. On
136   Mac, although some applications use MIME to describe clipboard
137   contents, it is more common to use Apple's UTI format.
138 
139   QMacPasteboardMime's role is to bridge the gap between MIME and UTI;
140   By subclasses this class, one can extend Qt's drag and drop
141   and clipboard handling to convert to and from unsupported, or proprietary, UTI formats.
142 
143   A subclass of QMacPasteboardMime will automatically be registered, and active, upon instantiation.
144 
145   Qt has predefined support for the following UTIs:
146   \list
147     \i public.utf8-plain-text - converts to "text/plain"
148     \i public.utf16-plain-text - converts to "text/plain"
149     \i public.html - converts to "text/html"
150     \i public.url - converts to "text/uri-list"
151     \i public.file-url - converts to "text/uri-list"
152     \i public.tiff - converts to "application/x-qt-image"
153     \i public.vcard - converts to "text/plain"
154     \i com.apple.traditional-mac-plain-text - converts to "text/plain"
155     \i com.apple.pict - converts to "application/x-qt-image"
156   \endlist
157 
158   When working with MIME data, Qt will interate through all instances of QMacPasteboardMime to
159   find an instance that can convert to, or from, a specific MIME type. It will do this by calling
160   canConvert() on each instance, starting with (and choosing) the last created instance first.
161   The actual conversions will be done by using convertToMime() and convertFromMime().
162 
163   \note The API uses the term "flavor" in some cases. This is for backwards
164   compatibility reasons, and should now be understood as UTIs.
165 */
166 
167 /*! \enum QMacPasteboardMime::QMacPasteboardMimeType
168     \internal
169 */
170 
171 /*!
172   Constructs a new conversion object of type \a t, adding it to the
173   globally accessed list of available convertors.
174 */
QMacPasteboardMime(char t)175 QMacPasteboardMime::QMacPasteboardMime(char t) : type(t)
176 {
177     globalMimeList()->append(this);
178 }
179 
180 /*!
181   Destroys a conversion object, removing it from the global
182   list of available convertors.
183 */
~QMacPasteboardMime()184 QMacPasteboardMime::~QMacPasteboardMime()
185 {
186     if(!QApplication::closingDown())
187         globalMimeList()->removeAll(this);
188 }
189 
190 class QMacPasteboardMimeAny : public QMacPasteboardMime {
191 private:
192 
193 public:
QMacPasteboardMimeAny()194     QMacPasteboardMimeAny() : QMacPasteboardMime(MIME_QT_CONVERTOR|MIME_ALL) {
195     }
~QMacPasteboardMimeAny()196     ~QMacPasteboardMimeAny() {
197     }
198     QString convertorName();
199 
200     QString flavorFor(const QString &mime);
201     QString mimeFor(QString flav);
202     bool canConvert(const QString &mime, QString flav);
203     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
204     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
205 };
206 
convertorName()207 QString QMacPasteboardMimeAny::convertorName()
208 {
209     return QLatin1String("Any-Mime");
210 }
211 
flavorFor(const QString & mime)212 QString QMacPasteboardMimeAny::flavorFor(const QString &mime)
213 {
214     // do not handle the mime type name in the drag pasteboard
215     if(mime == QLatin1String("application/x-qt-mime-type-name"))
216         return QString();
217     QString ret = QLatin1String("com.trolltech.anymime.") + mime;
218     return ret.replace(QLatin1Char('/'), QLatin1String("--"));
219 }
220 
mimeFor(QString flav)221 QString QMacPasteboardMimeAny::mimeFor(QString flav)
222 {
223     const QString any_prefix = QLatin1String("com.trolltech.anymime.");
224     if(flav.size() > any_prefix.length() && flav.startsWith(any_prefix))
225         return flav.mid(any_prefix.length()).replace(QLatin1String("--"), QLatin1String("/"));
226     return QString();
227 }
228 
canConvert(const QString & mime,QString flav)229 bool QMacPasteboardMimeAny::canConvert(const QString &mime, QString flav)
230 {
231     return mimeFor(flav) == mime;
232 }
233 
convertToMime(const QString & mime,QList<QByteArray> data,QString)234 QVariant QMacPasteboardMimeAny::convertToMime(const QString &mime, QList<QByteArray> data, QString)
235 {
236     if(data.count() > 1)
237         qWarning("QMacPasteboardMimeAny: Cannot handle multiple member data");
238     QVariant ret;
239     if (mime == QLatin1String("text/plain"))
240         ret = QString::fromUtf8(data.first());
241     else
242         ret = data.first();
243     return ret;
244 }
245 
convertFromMime(const QString & mime,QVariant data,QString)246 QList<QByteArray> QMacPasteboardMimeAny::convertFromMime(const QString &mime, QVariant data, QString)
247 {
248     QList<QByteArray> ret;
249     if (mime == QLatin1String("text/plain"))
250         ret.append(data.toString().toUtf8());
251     else
252         ret.append(data.toByteArray());
253     return ret;
254 }
255 
256 class QMacPasteboardMimeTypeName : public QMacPasteboardMime {
257 private:
258 
259 public:
QMacPasteboardMimeTypeName()260     QMacPasteboardMimeTypeName() : QMacPasteboardMime(MIME_QT_CONVERTOR|MIME_ALL) {
261     }
~QMacPasteboardMimeTypeName()262     ~QMacPasteboardMimeTypeName() {
263     }
264     QString convertorName();
265 
266     QString flavorFor(const QString &mime);
267     QString mimeFor(QString flav);
268     bool canConvert(const QString &mime, QString flav);
269     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
270     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
271 };
272 
convertorName()273 QString QMacPasteboardMimeTypeName::convertorName()
274 {
275     return QLatin1String("Qt-Mime-Type");
276 }
277 
flavorFor(const QString & mime)278 QString QMacPasteboardMimeTypeName::flavorFor(const QString &mime)
279 {
280     if(mime == QLatin1String("application/x-qt-mime-type-name"))
281         return QLatin1String("com.trolltech.qt.MimeTypeName");
282     return QString();
283 }
284 
mimeFor(QString)285 QString QMacPasteboardMimeTypeName::mimeFor(QString)
286 {
287     return QString();
288 }
289 
canConvert(const QString &,QString)290 bool QMacPasteboardMimeTypeName::canConvert(const QString &, QString)
291 {
292     return false;
293 }
294 
convertToMime(const QString &,QList<QByteArray>,QString)295 QVariant QMacPasteboardMimeTypeName::convertToMime(const QString &, QList<QByteArray>, QString)
296 {
297     QVariant ret;
298     return ret;
299 }
300 
convertFromMime(const QString &,QVariant,QString)301 QList<QByteArray> QMacPasteboardMimeTypeName::convertFromMime(const QString &, QVariant, QString)
302 {
303     QList<QByteArray> ret;
304     ret.append(QString("x-qt-mime-type-name").toUtf8());
305     return ret;
306 }
307 
308 class QMacPasteboardMimePlainText : public QMacPasteboardMime {
309 public:
QMacPasteboardMimePlainText()310     QMacPasteboardMimePlainText() : QMacPasteboardMime(MIME_ALL) { }
311     QString convertorName();
312 
313     QString flavorFor(const QString &mime);
314     QString mimeFor(QString flav);
315     bool canConvert(const QString &mime, QString flav);
316     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
317     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
318 };
319 
convertorName()320 QString QMacPasteboardMimePlainText::convertorName()
321 {
322     return QLatin1String("PlainText");
323 }
324 
flavorFor(const QString & mime)325 QString QMacPasteboardMimePlainText::flavorFor(const QString &mime)
326 {
327     if (mime == QLatin1String("text/plain"))
328         return QLatin1String("com.apple.traditional-mac-plain-text");
329     return QString();
330 }
331 
mimeFor(QString flav)332 QString QMacPasteboardMimePlainText::mimeFor(QString flav)
333 {
334     if (flav == QLatin1String("com.apple.traditional-mac-plain-text"))
335         return QLatin1String("text/plain");
336     return QString();
337 }
338 
canConvert(const QString & mime,QString flav)339 bool QMacPasteboardMimePlainText::canConvert(const QString &mime, QString flav)
340 {
341     return flavorFor(mime) == flav;
342 }
343 
convertToMime(const QString & mimetype,QList<QByteArray> data,QString flavor)344 QVariant QMacPasteboardMimePlainText::convertToMime(const QString &mimetype, QList<QByteArray> data, QString flavor)
345 {
346     if(data.count() > 1)
347         qWarning("QMacPasteboardMimePlainText: Cannot handle multiple member data");
348     const QByteArray &firstData = data.first();
349     QVariant ret;
350     if(flavor == QCFString(QLatin1String("com.apple.traditional-mac-plain-text"))) {
351         QCFString str(CFStringCreateWithBytes(kCFAllocatorDefault,
352                                              reinterpret_cast<const UInt8 *>(firstData.constData()),
353                                              firstData.size(), CFStringGetSystemEncoding(), false));
354         ret = QString(str);
355     } else {
356         qWarning("QMime::convertToMime: unhandled mimetype: %s", qPrintable(mimetype));
357     }
358     return ret;
359 }
360 
convertFromMime(const QString &,QVariant data,QString flavor)361 QList<QByteArray> QMacPasteboardMimePlainText::convertFromMime(const QString &, QVariant data, QString flavor)
362 {
363     QList<QByteArray> ret;
364     QString string = data.toString();
365     if(flavor == QCFString(QLatin1String("com.apple.traditional-mac-plain-text")))
366         ret.append(string.toLatin1());
367     return ret;
368 }
369 
370 class QMacPasteboardMimeUnicodeText : public QMacPasteboardMime {
371 public:
QMacPasteboardMimeUnicodeText()372     QMacPasteboardMimeUnicodeText() : QMacPasteboardMime(MIME_ALL) { }
373     QString convertorName();
374 
375     QString flavorFor(const QString &mime);
376     QString mimeFor(QString flav);
377     bool canConvert(const QString &mime, QString flav);
378     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
379     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
380 };
381 
convertorName()382 QString QMacPasteboardMimeUnicodeText::convertorName()
383 {
384     return QLatin1String("UnicodeText");
385 }
386 
flavorFor(const QString & mime)387 QString QMacPasteboardMimeUnicodeText::flavorFor(const QString &mime)
388 {
389     if (mime == QLatin1String("text/plain"))
390         return QLatin1String("public.utf16-plain-text");
391     int i = mime.indexOf(QLatin1String("charset="));
392     if (i >= 0) {
393         QString cs(mime.mid(i+8).toLower());
394         i = cs.indexOf(QLatin1Char(';'));
395         if (i>=0)
396             cs = cs.left(i);
397         if (cs == QLatin1String("system"))
398             return QLatin1String("public.utf8-plain-text");
399         else if (cs == QLatin1String("iso-10646-ucs-2")
400                  || cs == QLatin1String("utf16"))
401             return QLatin1String("public.utf16-plain-text");
402     }
403     return QString();
404 }
405 
mimeFor(QString flav)406 QString QMacPasteboardMimeUnicodeText::mimeFor(QString flav)
407 {
408     if (flav == QLatin1String("public.utf16-plain-text") || flav == QLatin1String("public.utf8-plain-text"))
409         return QLatin1String("text/plain");
410     return QString();
411 }
412 
canConvert(const QString & mime,QString flav)413 bool QMacPasteboardMimeUnicodeText::canConvert(const QString &mime, QString flav)
414 {
415     return flavorFor(mime) == flav;
416 }
417 
convertToMime(const QString & mimetype,QList<QByteArray> data,QString flavor)418 QVariant QMacPasteboardMimeUnicodeText::convertToMime(const QString &mimetype, QList<QByteArray> data, QString flavor)
419 {
420     if(data.count() > 1)
421         qWarning("QMacPasteboardMimeUnicodeText: Cannot handle multiple member data");
422     const QByteArray &firstData = data.first();
423     // I can only handle two types (system and unicode) so deal with them that way
424     QVariant ret;
425     if(flavor == QLatin1String("public.utf8-plain-text")) {
426         QCFString str(CFStringCreateWithBytes(kCFAllocatorDefault,
427                                              reinterpret_cast<const UInt8 *>(firstData.constData()),
428                                              firstData.size(), CFStringGetSystemEncoding(), false));
429         ret = QString(str);
430     } else if (flavor == QLatin1String("public.utf16-plain-text")) {
431         ret = QString(reinterpret_cast<const QChar *>(firstData.constData()),
432                       firstData.size() / sizeof(QChar));
433     } else {
434         qWarning("QMime::convertToMime: unhandled mimetype: %s", qPrintable(mimetype));
435     }
436     return ret;
437 }
438 
convertFromMime(const QString &,QVariant data,QString flavor)439 QList<QByteArray> QMacPasteboardMimeUnicodeText::convertFromMime(const QString &, QVariant data, QString flavor)
440 {
441     QList<QByteArray> ret;
442     QString string = data.toString();
443     if(flavor == QLatin1String("public.utf8-plain-text"))
444         ret.append(string.toUtf8());
445     else if (flavor == QLatin1String("public.utf16-plain-text"))
446         ret.append(QByteArray((char*)string.utf16(), string.length()*2));
447     return ret;
448 }
449 
450 class QMacPasteboardMimeHTMLText : public QMacPasteboardMime {
451 public:
QMacPasteboardMimeHTMLText()452     QMacPasteboardMimeHTMLText() : QMacPasteboardMime(MIME_ALL) { }
453     QString convertorName();
454 
455     QString flavorFor(const QString &mime);
456     QString mimeFor(QString flav);
457     bool canConvert(const QString &mime, QString flav);
458     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
459     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
460 };
461 
convertorName()462 QString QMacPasteboardMimeHTMLText::convertorName()
463 {
464     return QLatin1String("HTML");
465 }
466 
flavorFor(const QString & mime)467 QString QMacPasteboardMimeHTMLText::flavorFor(const QString &mime)
468 {
469     if (mime == QLatin1String("text/html"))
470         return QLatin1String("public.html");
471     return QString();
472 }
473 
mimeFor(QString flav)474 QString QMacPasteboardMimeHTMLText::mimeFor(QString flav)
475 {
476     if (flav == QLatin1String("public.html"))
477         return QLatin1String("text/html");
478     return QString();
479 }
480 
canConvert(const QString & mime,QString flav)481 bool QMacPasteboardMimeHTMLText::canConvert(const QString &mime, QString flav)
482 {
483     return flavorFor(mime) == flav;
484 }
485 
convertToMime(const QString & mimeType,QList<QByteArray> data,QString flavor)486 QVariant QMacPasteboardMimeHTMLText::convertToMime(const QString &mimeType, QList<QByteArray> data, QString flavor)
487 {
488     if (!canConvert(mimeType, flavor))
489         return QVariant();
490     if (data.count() > 1)
491         qWarning("QMacPasteboardMimeHTMLText: Cannot handle multiple member data");
492     return data.first();
493 }
494 
convertFromMime(const QString & mime,QVariant data,QString flavor)495 QList<QByteArray> QMacPasteboardMimeHTMLText::convertFromMime(const QString &mime, QVariant data, QString flavor)
496 {
497     QList<QByteArray> ret;
498     if (!canConvert(mime, flavor))
499         return ret;
500     ret.append(data.toByteArray());
501     return ret;
502 }
503 
504 
505 #ifdef Q_WS_MAC32
506 
507 // This can be removed once 10.6 is the minimum (or we have to require 64-bit) whichever comes first.
508 
509 typedef ComponentResult (*PtrGraphicsImportSetDataHandle)(GraphicsImportComponent, Handle);
510 typedef ComponentResult (*PtrGraphicsImportCreateCGImage)(GraphicsImportComponent, CGImageRef*, UInt32);
511 typedef ComponentResult (*PtrGraphicsExportSetInputCGImage)(GraphicsExportComponent, CGImageRef);
512 typedef ComponentResult (*PtrGraphicsExportSetOutputHandle)(GraphicsExportComponent, Handle);
513 typedef ComponentResult (*PtrGraphicsExportDoExport)(GraphicsExportComponent, unsigned long *);
514 
515 static PtrGraphicsImportSetDataHandle ptrGraphicsImportSetDataHandle = 0;
516 static PtrGraphicsImportCreateCGImage ptrGraphicsImportCreateCGImage = 0;
517 static PtrGraphicsExportSetInputCGImage ptrGraphicsExportSetInputCGImage = 0;
518 static PtrGraphicsExportSetOutputHandle ptrGraphicsExportSetOutputHandle = 0;
519 static PtrGraphicsExportDoExport ptrGraphicsExportDoExport = 0;
520 
resolveMimeQuickTimeSymbols()521 static bool resolveMimeQuickTimeSymbols()
522 {
523     static bool triedResolve = false;
524     if (!triedResolve) {
525         QLibrary library(QLatin1String("/System/Library/Frameworks/QuickTime.framework/QuickTime"));
526         ptrGraphicsImportSetDataHandle = reinterpret_cast<PtrGraphicsImportSetDataHandle>(library.resolve("GraphicsImportSetDataHandle"));
527         ptrGraphicsImportCreateCGImage = reinterpret_cast<PtrGraphicsImportCreateCGImage>(library.resolve("GraphicsImportCreateCGImage"));
528         ptrGraphicsExportSetInputCGImage = reinterpret_cast<PtrGraphicsExportSetInputCGImage>(library.resolve("GraphicsExportSetInputCGImage"));
529         ptrGraphicsExportSetOutputHandle = reinterpret_cast<PtrGraphicsExportSetOutputHandle>(library.resolve("GraphicsExportSetOutputHandle"));
530         ptrGraphicsExportDoExport = reinterpret_cast<PtrGraphicsExportDoExport>(library.resolve("GraphicsExportDoExport"));
531         triedResolve = true;
532     }
533 
534     return ptrGraphicsImportSetDataHandle != 0
535            && ptrGraphicsImportCreateCGImage != 0 && ptrGraphicsExportSetInputCGImage != 0
536            && ptrGraphicsExportSetOutputHandle != 0 && ptrGraphicsExportDoExport != 0;
537 }
538 
539 class QMacPasteboardMimePict : public QMacPasteboardMime {
540 public:
QMacPasteboardMimePict()541     QMacPasteboardMimePict() : QMacPasteboardMime(MIME_ALL) { }
542     QString convertorName();
543 
544     QString flavorFor(const QString &mime);
545     QString mimeFor(QString flav);
546     bool canConvert(const QString &mime, QString flav);
547     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
548     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
549 };
550 
convertorName()551 QString QMacPasteboardMimePict::convertorName()
552 {
553     return QLatin1String("Pict");
554 }
555 
flavorFor(const QString & mime)556 QString QMacPasteboardMimePict::flavorFor(const QString &mime)
557 {
558     if(mime.startsWith(QLatin1String("application/x-qt-image")))
559         return QLatin1String("com.apple.pict");
560     return QString();
561 }
562 
mimeFor(QString flav)563 QString QMacPasteboardMimePict::mimeFor(QString flav)
564 {
565     if(flav == QLatin1String("com.apple.pict"))
566         return QLatin1String("application/x-qt-image");
567     return QString();
568 }
569 
canConvert(const QString & mime,QString flav)570 bool QMacPasteboardMimePict::canConvert(const QString &mime, QString flav)
571 {
572     return flav == QLatin1String("com.apple.pict")
573             && mime == QLatin1String("application/x-qt-image");
574 }
575 
576 
convertToMime(const QString & mime,QList<QByteArray> data,QString flav)577 QVariant QMacPasteboardMimePict::convertToMime(const QString &mime, QList<QByteArray> data, QString flav)
578 {
579     if(data.count() > 1)
580         qWarning("QMacPasteboardMimePict: Cannot handle multiple member data");
581     QVariant ret;
582     if (!resolveMimeQuickTimeSymbols())
583         return ret;
584 
585     if(!canConvert(mime, flav))
586         return ret;
587     const QByteArray &a = data.first();
588 
589     // This function expects the 512 header (just to skip it, so create the extra space for it).
590     Handle pic = NewHandle(a.size() + 512);
591     memcpy(*pic + 512, a.constData(), a.size());
592 
593     GraphicsImportComponent graphicsImporter;
594     ComponentResult result = OpenADefaultComponent(GraphicsImporterComponentType,
595                                                    kQTFileTypePicture, &graphicsImporter);
596     QCFType<CGImageRef> cgImage;
597     if (!result)
598         result = ptrGraphicsImportSetDataHandle(graphicsImporter, pic);
599     if (!result)
600         result = ptrGraphicsImportCreateCGImage(graphicsImporter, &cgImage,
601                                              kGraphicsImportCreateCGImageUsingCurrentSettings);
602     if (!result)
603         ret = QVariant(QPixmap::fromMacCGImageRef(cgImage).toImage());
604     CloseComponent(graphicsImporter);
605     DisposeHandle(pic);
606     return ret;
607 }
608 
convertFromMime(const QString & mime,QVariant variant,QString flav)609 QList<QByteArray> QMacPasteboardMimePict::convertFromMime(const QString &mime, QVariant variant,
610                                                           QString flav)
611 {
612     QList<QByteArray> ret;
613     if (!resolveMimeQuickTimeSymbols())
614         return ret;
615 
616     if (!canConvert(mime, flav))
617         return ret;
618     QCFType<CGImageRef> cgimage = qt_mac_createCGImageFromQImage(qvariant_cast<QImage>(variant));
619     Handle pic = NewHandle(0);
620     GraphicsExportComponent graphicsExporter;
621     ComponentResult result = OpenADefaultComponent(GraphicsExporterComponentType,
622                                                    kQTFileTypePicture, &graphicsExporter);
623     if (!result) {
624         unsigned long sizeWritten;
625         result = ptrGraphicsExportSetInputCGImage(graphicsExporter, cgimage);
626         if (!result)
627             result = ptrGraphicsExportSetOutputHandle(graphicsExporter, pic);
628         if (!result)
629             result = ptrGraphicsExportDoExport(graphicsExporter, &sizeWritten);
630 
631         CloseComponent(graphicsExporter);
632     }
633 
634     int size = GetHandleSize((Handle)pic);
635     // Skip the Picture File header (512 bytes) and feed the raw data
636     QByteArray ar(reinterpret_cast<char *>(*pic + 512), size - 512);
637     ret.append(ar);
638     DisposeHandle(pic);
639     return ret;
640 }
641 
642 
643 #endif //Q_WS_MAC32
644 
645 class QMacPasteboardMimeTiff : public QMacPasteboardMime {
646 public:
QMacPasteboardMimeTiff()647     QMacPasteboardMimeTiff() : QMacPasteboardMime(MIME_ALL) { }
648     QString convertorName();
649 
650     QString flavorFor(const QString &mime);
651     QString mimeFor(QString flav);
652     bool canConvert(const QString &mime, QString flav);
653     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
654     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
655 };
656 
convertorName()657 QString QMacPasteboardMimeTiff::convertorName()
658 {
659     return QLatin1String("Tiff");
660 }
661 
flavorFor(const QString & mime)662 QString QMacPasteboardMimeTiff::flavorFor(const QString &mime)
663 {
664     if(mime.startsWith(QLatin1String("application/x-qt-image")))
665         return QLatin1String("public.tiff");
666     return QString();
667 }
668 
mimeFor(QString flav)669 QString QMacPasteboardMimeTiff::mimeFor(QString flav)
670 {
671     if(flav == QLatin1String("public.tiff"))
672         return QLatin1String("application/x-qt-image");
673     return QString();
674 }
675 
canConvert(const QString & mime,QString flav)676 bool QMacPasteboardMimeTiff::canConvert(const QString &mime, QString flav)
677 {
678     return flav == QLatin1String("public.tiff") && mime == QLatin1String("application/x-qt-image");
679 }
680 
convertToMime(const QString & mime,QList<QByteArray> data,QString flav)681 QVariant QMacPasteboardMimeTiff::convertToMime(const QString &mime, QList<QByteArray> data, QString flav)
682 {
683     if(data.count() > 1)
684         qWarning("QMacPasteboardMimeTiff: Cannot handle multiple member data");
685     QVariant ret;
686     if (!canConvert(mime, flav))
687         return ret;
688     const QByteArray &a = data.first();
689     QCFType<CGImageRef> image;
690     QCFType<CFDataRef> tiffData = CFDataCreateWithBytesNoCopy(0,
691                                                 reinterpret_cast<const UInt8 *>(a.constData()),
692                                                 a.size(), kCFAllocatorNull);
693     QCFType<CGImageSourceRef> imageSource = CGImageSourceCreateWithData(tiffData, 0);
694     image = CGImageSourceCreateImageAtIndex(imageSource, 0, 0);
695 
696     if (image != 0)
697         ret = QVariant(QPixmap::fromMacCGImageRef(image).toImage());
698     return ret;
699 }
700 
convertFromMime(const QString & mime,QVariant variant,QString flav)701 QList<QByteArray> QMacPasteboardMimeTiff::convertFromMime(const QString &mime, QVariant variant, QString flav)
702 {
703     QList<QByteArray> ret;
704     if (!canConvert(mime, flav))
705         return ret;
706 
707     QImage img = qvariant_cast<QImage>(variant);
708     QCFType<CGImageRef> cgimage = qt_mac_createCGImageFromQImage(img);
709 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
710     if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
711         QCFType<CFMutableDataRef> data = CFDataCreateMutable(0, 0);
712         QCFType<CGImageDestinationRef> imageDestination = CGImageDestinationCreateWithData(data, kUTTypeTIFF, 1, 0);
713         if (imageDestination != 0) {
714             CFTypeRef keys[2];
715             QCFType<CFTypeRef> values[2];
716             QCFType<CFDictionaryRef> options;
717             keys[0] = kCGImagePropertyPixelWidth;
718             keys[1] = kCGImagePropertyPixelHeight;
719             int width = img.width();
720             int height = img.height();
721             values[0] = CFNumberCreate(0, kCFNumberIntType, &width);
722             values[1] = CFNumberCreate(0, kCFNumberIntType, &height);
723             options = CFDictionaryCreate(0, reinterpret_cast<const void **>(keys),
724                                          reinterpret_cast<const void **>(values), 2,
725                                          &kCFTypeDictionaryKeyCallBacks,
726                                          &kCFTypeDictionaryValueCallBacks);
727             CGImageDestinationAddImage(imageDestination, cgimage, options);
728             CGImageDestinationFinalize(imageDestination);
729         }
730         QByteArray ar(CFDataGetLength(data), 0);
731         CFDataGetBytes(data,
732                 CFRangeMake(0, ar.size()),
733                 reinterpret_cast<UInt8 *>(ar.data()));
734         ret.append(ar);
735     } else
736 #endif
737     {
738 #ifdef Q_WS_MAC32
739         Handle tiff = NewHandle(0);
740         if (resolveMimeQuickTimeSymbols()) {
741             GraphicsExportComponent graphicsExporter;
742             ComponentResult result = OpenADefaultComponent(GraphicsExporterComponentType,
743                                                            kQTFileTypeTIFF, &graphicsExporter);
744             if (!result) {
745                 unsigned long sizeWritten;
746                 result = ptrGraphicsExportSetInputCGImage(graphicsExporter, cgimage);
747                 if (!result)
748                     result = ptrGraphicsExportSetOutputHandle(graphicsExporter, tiff);
749                 if (!result)
750                     result = ptrGraphicsExportDoExport(graphicsExporter, &sizeWritten);
751 
752                 CloseComponent(graphicsExporter);
753             }
754         }
755         int size = GetHandleSize((Handle)tiff);
756         QByteArray ar(reinterpret_cast<char *>(*tiff), size);
757         ret.append(ar);
758         DisposeHandle(tiff);
759 #endif
760     }
761     return ret;
762 }
763 
764 
765 class QMacPasteboardMimeFileUri : public QMacPasteboardMime {
766 public:
QMacPasteboardMimeFileUri()767     QMacPasteboardMimeFileUri() : QMacPasteboardMime(MIME_ALL) { }
768     QString convertorName();
769 
770     QString flavorFor(const QString &mime);
771     QString mimeFor(QString flav);
772     bool canConvert(const QString &mime, QString flav);
773     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
774     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
775 };
776 
convertorName()777 QString QMacPasteboardMimeFileUri::convertorName()
778 {
779     return QLatin1String("FileURL");
780 }
781 
flavorFor(const QString & mime)782 QString QMacPasteboardMimeFileUri::flavorFor(const QString &mime)
783 {
784     if (mime == QLatin1String("text/uri-list"))
785         return QCFString(UTTypeCreatePreferredIdentifierForTag(kUTTagClassOSType, CFSTR("furl"), 0));
786     return QString();
787 }
788 
mimeFor(QString flav)789 QString QMacPasteboardMimeFileUri::mimeFor(QString flav)
790 {
791     if (flav == QCFString(UTTypeCreatePreferredIdentifierForTag(kUTTagClassOSType, CFSTR("furl"), 0)))
792         return QLatin1String("text/uri-list");
793     return QString();
794 }
795 
canConvert(const QString & mime,QString flav)796 bool QMacPasteboardMimeFileUri::canConvert(const QString &mime, QString flav)
797 {
798     return mime == QLatin1String("text/uri-list")
799             && flav == QCFString(UTTypeCreatePreferredIdentifierForTag(kUTTagClassOSType, CFSTR("furl"), 0));
800 }
801 
convertToMime(const QString & mime,QList<QByteArray> data,QString flav)802 QVariant QMacPasteboardMimeFileUri::convertToMime(const QString &mime, QList<QByteArray> data, QString flav)
803 {
804     if(!canConvert(mime, flav))
805         return QVariant();
806     QList<QVariant> ret;
807     for(int i = 0; i < data.size(); ++i) {
808         QUrl url = QUrl::fromEncoded(data.at(i));
809         if (url.host().toLower() == QLatin1String("localhost"))
810             url.setHost(QString());
811         url.setPath(url.path().normalized(QString::NormalizationForm_C));
812         ret.append(url);
813     }
814     return QVariant(ret);
815 }
816 
convertFromMime(const QString & mime,QVariant data,QString flav)817 QList<QByteArray> QMacPasteboardMimeFileUri::convertFromMime(const QString &mime, QVariant data, QString flav)
818 {
819     QList<QByteArray> ret;
820     if (!canConvert(mime, flav))
821         return ret;
822     QList<QVariant> urls = data.toList();
823     for(int i = 0; i < urls.size(); ++i) {
824         QUrl url = urls.at(i).toUrl();
825         if (url.scheme().isEmpty())
826             url.setScheme(QLatin1String("file"));
827         if (url.scheme().toLower() == QLatin1String("file")) {
828             if (url.host().isEmpty())
829                 url.setHost(QLatin1String("localhost"));
830             url.setPath(url.path().normalized(QString::NormalizationForm_D));
831         }
832         ret.append(url.toEncoded());
833     }
834     return ret;
835 }
836 
837 class QMacPasteboardMimeUrl : public QMacPasteboardMime {
838 public:
QMacPasteboardMimeUrl()839     QMacPasteboardMimeUrl() : QMacPasteboardMime(MIME_ALL) { }
840     QString convertorName();
841 
842     QString flavorFor(const QString &mime);
843     QString mimeFor(QString flav);
844     bool canConvert(const QString &mime, QString flav);
845     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
846     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
847 };
848 
convertorName()849 QString QMacPasteboardMimeUrl::convertorName()
850 {
851     return QLatin1String("URL");
852 }
853 
flavorFor(const QString & mime)854 QString QMacPasteboardMimeUrl::flavorFor(const QString &mime)
855 {
856     if(mime.startsWith(QLatin1String("text/uri-list")))
857         return QLatin1String("public.url");
858     return QString();
859 }
860 
mimeFor(QString flav)861 QString QMacPasteboardMimeUrl::mimeFor(QString flav)
862 {
863     if(flav == QLatin1String("public.url"))
864         return QLatin1String("text/uri-list");
865     return QString();
866 }
867 
canConvert(const QString & mime,QString flav)868 bool QMacPasteboardMimeUrl::canConvert(const QString &mime, QString flav)
869 {
870     return flav == QLatin1String("public.url")
871             && mime == QLatin1String("text/uri-list");
872 }
873 
convertToMime(const QString & mime,QList<QByteArray> data,QString flav)874 QVariant QMacPasteboardMimeUrl::convertToMime(const QString &mime, QList<QByteArray> data, QString flav)
875 {
876     if(!canConvert(mime, flav))
877         return QVariant();
878 
879     QList<QVariant> ret;
880     for (int i=0; i<data.size(); ++i) {
881         QUrl url = QUrl::fromEncoded(data.at(i));
882         if (url.host().toLower() == QLatin1String("localhost"))
883             url.setHost(QString());
884         url.setPath(url.path().normalized(QString::NormalizationForm_C));
885         ret.append(url);
886     }
887     return QVariant(ret);
888 }
889 
convertFromMime(const QString & mime,QVariant data,QString flav)890 QList<QByteArray> QMacPasteboardMimeUrl::convertFromMime(const QString &mime, QVariant data, QString flav)
891 {
892     QList<QByteArray> ret;
893     if (!canConvert(mime, flav))
894         return ret;
895 
896     QList<QVariant> urls = data.toList();
897     for(int i=0; i<urls.size(); ++i) {
898         QUrl url = urls.at(i).toUrl();
899         if (url.scheme().isEmpty())
900             url.setScheme(QLatin1String("file"));
901         if (url.scheme().toLower() == QLatin1String("file")) {
902             if (url.host().isEmpty())
903                 url.setHost(QLatin1String("localhost"));
904             url.setPath(url.path().normalized(QString::NormalizationForm_D));
905         }
906         ret.append(url.toEncoded());
907     }
908     return ret;
909 }
910 
911 class QMacPasteboardMimeVCard : public QMacPasteboardMime
912 {
913 public:
QMacPasteboardMimeVCard()914     QMacPasteboardMimeVCard() : QMacPasteboardMime(MIME_ALL){ }
915     QString convertorName();
916 
917     QString flavorFor(const QString &mime);
918     QString mimeFor(QString flav);
919     bool canConvert(const QString &mime, QString flav);
920     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
921     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
922 };
923 
convertorName()924 QString QMacPasteboardMimeVCard::convertorName()
925 {
926     return QString("VCard");
927 }
928 
canConvert(const QString & mime,QString flav)929 bool QMacPasteboardMimeVCard::canConvert(const QString &mime, QString flav)
930 {
931     return mimeFor(flav) == mime;
932 }
933 
flavorFor(const QString & mime)934 QString QMacPasteboardMimeVCard::flavorFor(const QString &mime)
935 {
936     if(mime.startsWith(QLatin1String("text/plain")))
937         return QLatin1String("public.vcard");
938     return QString();
939 }
940 
mimeFor(QString flav)941 QString QMacPasteboardMimeVCard::mimeFor(QString flav)
942 {
943     if (flav == QLatin1String("public.vcard"))
944         return QLatin1String("text/plain");
945     return QString();
946 }
947 
convertToMime(const QString & mime,QList<QByteArray> data,QString)948 QVariant QMacPasteboardMimeVCard::convertToMime(const QString &mime, QList<QByteArray> data, QString)
949 {
950     QByteArray cards;
951     if (mime == QLatin1String("text/plain")) {
952         for (int i=0; i<data.size(); ++i)
953             cards += data[i];
954     }
955     return QVariant(cards);
956 }
957 
convertFromMime(const QString & mime,QVariant data,QString)958 QList<QByteArray> QMacPasteboardMimeVCard::convertFromMime(const QString &mime, QVariant data, QString)
959 {
960     QList<QByteArray> ret;
961     if (mime == QLatin1String("text/plain"))
962         ret.append(data.toString().toUtf8());
963     return ret;
964 }
965 
966 #ifdef QT3_SUPPORT
967 class QMacPasteboardMimeQt3Any : public QMacPasteboardMime {
968 private:
969     int current_max;
970     QFile library_file;
971     QDateTime mime_registry_loaded;
972     QMap<QString, int> mime_registry;
973     int registerMimeType(const QString &mime);
974     bool loadMimeRegistry();
975 
976 public:
QMacPasteboardMimeQt3Any()977     QMacPasteboardMimeQt3Any() : QMacPasteboardMime(MIME_QT3_CONVERTOR) {
978         current_max = 'QT00';
979     }
~QMacPasteboardMimeQt3Any()980     ~QMacPasteboardMimeQt3Any() {
981     }
982     QString convertorName();
983 
984     QString flavorFor(const QString &mime);
985     QString mimeFor(QString flav);
986     bool canConvert(const QString &mime, QString flav);
987     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
988     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
989 };
990 
qt_mac_openMimeRegistry(bool global,QIODevice::OpenMode mode,QFile & file)991 static bool qt_mac_openMimeRegistry(bool global, QIODevice::OpenMode mode, QFile &file)
992 {
993     QString dir = QLatin1String("/Library/Qt");
994     if(!global)
995         dir.prepend(QDir::homePath());
996     file.setFileName(dir + QLatin1String("/.mime_types"));
997     if(mode != QIODevice::ReadOnly) {
998         if(!QFile::exists(dir)) {
999             // Do it with a system call as I don't see much worth in
1000             // doing it with QDir since we have to chmod anyway.
1001             bool success = ::mkdir(dir.toLocal8Bit().constData(), S_IRUSR | S_IWUSR | S_IXUSR) == 0;
1002             if (success)
1003                 success = ::chmod(dir.toLocal8Bit().constData(), S_IRUSR | S_IWUSR | S_IXUSR
1004                                       | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH) == 0;
1005             if (!success)
1006                 return false;
1007         }
1008         if (!file.exists()) {
1009             // Create the file and chmod it so that everyone can write to it.
1010             int fd = ::open(file.fileName().toLocal8Bit().constData(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
1011             bool success = fd != -1;
1012             if (success)
1013                 success = ::fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) == 0;
1014             if (fd != -1)
1015                 ::close(fd);
1016             if(!success)
1017                 return false;
1018         }
1019     }
1020     return file.open(mode);
1021 }
1022 
qt_mac_loadMimeRegistry(QFile & file,QMap<QString,int> & registry,int & max)1023 static void qt_mac_loadMimeRegistry(QFile &file, QMap<QString, int> &registry, int &max)
1024 {
1025     file.reset();
1026     QTextStream stream(&file);
1027     while(!stream.atEnd()) {
1028 	QString mime = stream.readLine();
1029 	int mactype = stream.readLine().toInt();
1030 	if(mactype > max)
1031 	    max = mactype;
1032 	registry.insert(mime, mactype);
1033     }
1034 }
1035 
loadMimeRegistry()1036 bool QMacPasteboardMimeQt3Any::loadMimeRegistry()
1037 {
1038     if(!library_file.isOpen()) {
1039         if(!qt_mac_openMimeRegistry(true, QIODevice::ReadWrite, library_file)) {
1040             QFile global;
1041             if(qt_mac_openMimeRegistry(true, QIODevice::ReadOnly, global)) {
1042                 qt_mac_loadMimeRegistry(global, mime_registry, current_max);
1043                 global.close();
1044             }
1045             if(!qt_mac_openMimeRegistry(false, QIODevice::ReadWrite, library_file)) {
1046                 qWarning("QMacPasteboardMimeAnyQt3Mime: Failure to open mime resources %s -- %s", library_file.fileName().toLatin1().constData(),
1047                          library_file.errorString().toLatin1().constData());
1048                 return false;
1049             }
1050         }
1051     }
1052 
1053     QFileInfo fi(library_file);
1054     if(!mime_registry_loaded.isNull() && mime_registry_loaded == fi.lastModified())
1055         return true;
1056     mime_registry_loaded = fi.lastModified();
1057     qt_mac_loadMimeRegistry(library_file, mime_registry, current_max);
1058     return true;
1059 }
1060 
registerMimeType(const QString & mime)1061 int QMacPasteboardMimeQt3Any::registerMimeType(const QString &mime)
1062 {
1063     if(!mime_registry.contains(mime)) {
1064         if(!loadMimeRegistry()) {
1065             qWarning("QMacPasteboardMimeAnyQt3Mime: Internal error");
1066             return 0;
1067         }
1068         if(!mime_registry.contains(mime)) {
1069             if(!library_file.isOpen()) {
1070                 if(!library_file.open(QIODevice::WriteOnly)) {
1071                     qWarning("QMacPasteboardMimeAnyQt3Mime: Failure to open %s -- %s", library_file.fileName().toLatin1().constData(),
1072                              library_file.errorString().toLatin1().constData());
1073                     return false;
1074                 }
1075             }
1076             int ret = ++current_max;
1077             mime_registry_loaded = QFileInfo(library_file).lastModified();
1078             QTextStream stream(&library_file);
1079             stream << mime << endl;
1080             stream << ret << endl;
1081             mime_registry.insert(mime, ret);
1082             library_file.flush(); //flush and set mtime
1083             return ret;
1084         }
1085     }
1086     return mime_registry[mime];
1087 }
1088 
convertorName()1089 QString QMacPasteboardMimeQt3Any::convertorName()
1090 {
1091     return QLatin1String("Qt3-Any-Mime");
1092 }
1093 
flavorFor(const QString & mime)1094 QString QMacPasteboardMimeQt3Any::flavorFor(const QString &mime)
1095 {
1096     const int os_flav = registerMimeType(mime);
1097     QCFType<CFArrayRef> ids = UTTypeCreateAllIdentifiersForTag(0, kUTTagClassOSType,
1098                                                                QCFString(UTCreateStringForOSType(os_flav)));
1099     if(ids) {
1100         const int type_count = CFArrayGetCount(ids);
1101         if(type_count) {
1102             if(type_count > 1)
1103                 qDebug("Can't happen!");
1104             return QCFString::toQString((CFStringRef)CFArrayGetValueAtIndex(ids, 0));
1105         }
1106     }
1107     return QString();
1108 }
1109 
mimeFor(QString flav)1110 QString QMacPasteboardMimeQt3Any::mimeFor(QString flav)
1111 {
1112     loadMimeRegistry();
1113     const int os_flav = UTGetOSTypeFromString(UTTypeCopyPreferredTagWithClass(QCFString(flav), kUTTagClassOSType));
1114     for(QMap<QString, int>::const_iterator it = mime_registry.constBegin();
1115         it != mime_registry.constEnd(); ++it) {
1116         if(it.value() == os_flav)
1117             return QString::fromLatin1(it.key().toLatin1());
1118     }
1119     return QString();
1120 }
1121 
canConvert(const QString & mime,QString flav)1122 bool QMacPasteboardMimeQt3Any::canConvert(const QString &mime, QString flav)
1123 {
1124     loadMimeRegistry();
1125     const int os_flav = UTGetOSTypeFromString(UTTypeCopyPreferredTagWithClass(QCFString(flav), kUTTagClassOSType));
1126     if(mime_registry.contains(mime) && mime_registry[mime] == os_flav)
1127         return true;
1128     return false;
1129 }
1130 
convertToMime(const QString &,QList<QByteArray>,QString)1131 QVariant QMacPasteboardMimeQt3Any::convertToMime(const QString &, QList<QByteArray>, QString)
1132 {
1133     qWarning("QMacPasteboardMimeAnyQt3Mime: Cannot write anything!");
1134     return QVariant();
1135 }
1136 
convertFromMime(const QString & mime,QVariant data,QString)1137 QList<QByteArray> QMacPasteboardMimeQt3Any::convertFromMime(const QString &mime, QVariant data, QString)
1138 {
1139     QList<QByteArray> ret;
1140     if (mime == QLatin1String("text/plain")) {
1141         ret.append(data.toString().toUtf8());
1142     } else {
1143         ret.append(data.toByteArray());
1144     }
1145     return ret;
1146 }
1147 #endif
1148 
1149 /*!
1150   \internal
1151 
1152   This is an internal function.
1153 */
initialize()1154 void QMacPasteboardMime::initialize()
1155 {
1156     if(globalMimeList()->isEmpty()) {
1157         qAddPostRoutine(cleanup_mimes);
1158 
1159         //standard types that we wrap
1160         new QMacPasteboardMimeTiff;
1161 #ifdef Q_WS_MAC32
1162         // 10.6 does automatic synthesis to and from PICT to standard image types (like TIFF),
1163         // so don't bother doing it ourselves, especially since it's not available in 64-bit.
1164         if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_6)
1165             new QMacPasteboardMimePict;
1166 #endif
1167         new QMacPasteboardMimeUnicodeText;
1168         new QMacPasteboardMimePlainText;
1169         new QMacPasteboardMimeHTMLText;
1170         new QMacPasteboardMimeFileUri;
1171         new QMacPasteboardMimeUrl;
1172         new QMacPasteboardMimeTypeName;
1173         new QMacPasteboardMimeVCard;
1174         //make sure our "non-standard" types are always last! --Sam
1175         new QMacPasteboardMimeAny;
1176 #ifdef QT3_SUPPORT
1177         new QMacPasteboardMimeQt3Any;
1178 #endif
1179     }
1180 }
1181 
1182 /*!
1183   Returns the most-recently created QMacPasteboardMime of type \a t that can convert
1184   between the \a mime and \a flav formats.  Returns 0 if no such convertor
1185   exists.
1186 */
1187 QMacPasteboardMime*
convertor(uchar t,const QString & mime,QString flav)1188 QMacPasteboardMime::convertor(uchar t, const QString &mime, QString flav)
1189 {
1190     MimeList *mimes = globalMimeList();
1191     for(MimeList::const_iterator it = mimes->constBegin(); it != mimes->constEnd(); ++it) {
1192 #ifdef DEBUG_MIME_MAPS
1193         qDebug("QMacPasteboardMime::convertor: seeing if %s (%d) can convert %s to %d[%c%c%c%c] [%d]",
1194                (*it)->convertorName().toLatin1().constData(),
1195                (*it)->type & t, mime.toLatin1().constData(),
1196                flav, (flav >> 24) & 0xFF, (flav >> 16) & 0xFF, (flav >> 8) & 0xFF, (flav) & 0xFF,
1197                (*it)->canConvert(mime,flav));
1198         for(int i = 0; i < (*it)->countFlavors(); ++i) {
1199             int f = (*it)->flavor(i);
1200             qDebug("  %d) %d[%c%c%c%c] [%s]", i, f,
1201                    (f >> 24) & 0xFF, (f >> 16) & 0xFF, (f >> 8) & 0xFF, (f) & 0xFF,
1202                    (*it)->convertorName().toLatin1().constData());
1203         }
1204 #endif
1205         if(((*it)->type & t) && (*it)->canConvert(mime, flav))
1206             return (*it);
1207     }
1208     return 0;
1209 }
1210 /*!
1211   Returns a MIME type of type \a t for \a flav, or 0 if none exists.
1212 */
flavorToMime(uchar t,QString flav)1213 QString QMacPasteboardMime::flavorToMime(uchar t, QString flav)
1214 {
1215     MimeList *mimes = globalMimeList();
1216     for(MimeList::const_iterator it = mimes->constBegin(); it != mimes->constEnd(); ++it) {
1217 #ifdef DEBUG_MIME_MAPS
1218         qDebug("QMacMIme::flavorToMime: attempting %s (%d) for flavor %d[%c%c%c%c] [%s]",
1219                (*it)->convertorName().toLatin1().constData(),
1220                (*it)->type & t, flav, (flav >> 24) & 0xFF, (flav >> 16) & 0xFF, (flav >> 8) & 0xFF, (flav) & 0xFF,
1221                (*it)->mimeFor(flav).toLatin1().constData());
1222 
1223 #endif
1224         if((*it)->type & t) {
1225             QString mimeType = (*it)->mimeFor(flav);
1226             if(!mimeType.isNull())
1227                 return mimeType;
1228         }
1229     }
1230     return QString();
1231 }
1232 
1233 /*!
1234   Returns a list of all currently defined QMacPasteboardMime objects of type \a t.
1235 */
all(uchar t)1236 QList<QMacPasteboardMime*> QMacPasteboardMime::all(uchar t)
1237 {
1238     MimeList ret;
1239     MimeList *mimes = globalMimeList();
1240     for(MimeList::const_iterator it = mimes->constBegin(); it != mimes->constEnd(); ++it) {
1241         if((*it)->type & t)
1242             ret.append((*it));
1243     }
1244     return ret;
1245 }
1246 
1247 
1248 /*!
1249   \fn QString QMacPasteboardMime::convertorName()
1250 
1251   Returns a name for the convertor.
1252 
1253   All subclasses must reimplement this pure virtual function.
1254 */
1255 
1256 /*!
1257   \fn bool QMacPasteboardMime::canConvert(const QString &mime, QString flav)
1258 
1259   Returns true if the convertor can convert (both ways) between
1260   \a mime and \a flav; otherwise returns false.
1261 
1262   All subclasses must reimplement this pure virtual function.
1263 */
1264 
1265 /*!
1266   \fn QString QMacPasteboardMime::mimeFor(QString flav)
1267 
1268   Returns the MIME UTI used for Mac flavor \a flav, or 0 if this
1269   convertor does not support \a flav.
1270 
1271   All subclasses must reimplement this pure virtual function.
1272 */
1273 
1274 /*!
1275   \fn QString QMacPasteboardMime::flavorFor(const QString &mime)
1276 
1277   Returns the Mac UTI used for MIME type \a mime, or 0 if this
1278   convertor does not support \a mime.
1279 
1280   All subclasses must reimplement this pure virtual function.
1281 */
1282 
1283 /*!
1284     \fn QVariant QMacPasteboardMime::convertToMime(const QString &mime, QList<QByteArray> data, QString flav)
1285 
1286     Returns \a data converted from Mac UTI \a flav to MIME type \a
1287     mime.
1288 
1289     Note that Mac flavors must all be self-terminating. The input \a
1290     data may contain trailing data.
1291 
1292     All subclasses must reimplement this pure virtual function.
1293 */
1294 
1295 /*!
1296   \fn QList<QByteArray> QMacPasteboardMime::convertFromMime(const QString &mime, QVariant data, QString flav)
1297 
1298   Returns \a data converted from MIME type \a mime
1299     to Mac UTI \a flav.
1300 
1301   Note that Mac flavors must all be self-terminating.  The return
1302   value may contain trailing data.
1303 
1304   All subclasses must reimplement this pure virtual function.
1305 */
1306 
1307 
1308 QT_END_NAMESPACE
1309