Fixed crash in GL 2 paint engine on Intel Atom.
[profile/ivi/qtbase.git] / src / widgets / platforms / mac / qmime_mac.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
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;
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
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_WIDGETS_EXPORT void qRegisterDraggedTypes(const QStringList &types)
107 {
108     (*globalDraggedTypesList()) += types;
109 }
110
111 const QStringList& qEnabledDraggedTypes()
112 {
113     return (*globalDraggedTypesList());
114 }
115
116
117 /*****************************************************************************
118   QDnD debug facilities
119  *****************************************************************************/
120 //#define DEBUG_MIME_MAPS
121
122 //functions
123 extern QString qt_mac_from_pascal_string(const Str255);  //qglobal.cpp
124 extern void qt_mac_from_pascal_string(QString, Str255, TextEncoding encoding=0, int len=-1);  //qglobal.cpp
125
126 ScrapFlavorType qt_mac_mime_type = 'CUTE';
127 CFStringRef qt_mac_mime_typeUTI = CFSTR("com.pasteboard.trolltech.marker");
128
129 /*!
130   \class QMacPasteboardMime
131   \brief The QMacPasteboardMime class converts between a MIME type and a
132   \l{http://developer.apple.com/macosx/uniformtypeidentifiers.html}{Uniform
133   Type Identifier (UTI)} format.
134   \since 4.2
135
136   \ingroup draganddrop
137   \inmodule QtWidgets
138
139   Qt's drag and drop and clipboard facilities use the MIME
140   standard. On X11, this maps trivially to the Xdnd protocol. On
141   Mac, although some applications use MIME to describe clipboard
142   contents, it is more common to use Apple's UTI format.
143
144   QMacPasteboardMime's role is to bridge the gap between MIME and UTI;
145   By subclasses this class, one can extend Qt's drag and drop
146   and clipboard handling to convert to and from unsupported, or proprietary, UTI formats.
147
148   A subclass of QMacPasteboardMime will automatically be registered, and active, upon instantiation.
149
150   Qt has predefined support for the following UTIs:
151   \list
152     \i public.utf8-plain-text - converts to "text/plain"
153     \i public.utf16-plain-text - converts to "text/plain"
154     \i public.html - converts to "text/html"
155     \i public.url - converts to "text/uri-list"
156     \i public.file-url - converts to "text/uri-list"
157     \i public.tiff - converts to "application/x-qt-image"
158     \i public.vcard - converts to "text/plain"
159     \i com.apple.traditional-mac-plain-text - converts to "text/plain"
160     \i com.apple.pict - converts to "application/x-qt-image"
161   \endlist
162
163   When working with MIME data, Qt will interate through all instances of QMacPasteboardMime to
164   find an instance that can convert to, or from, a specific MIME type. It will do this by calling
165   canConvert() on each instance, starting with (and choosing) the last created instance first.
166   The actual conversions will be done by using convertToMime() and convertFromMime().
167
168   \note The API uses the term "flavor" in some cases. This is for backwards
169   compatibility reasons, and should now be understood as UTIs.
170 */
171
172 /*! \enum QMacPasteboardMime::QMacPasteboardMimeType
173     \internal
174 */
175
176 /*!
177   Constructs a new conversion object of type \a t, adding it to the
178   globally accessed list of available convertors.
179 */
180 QMacPasteboardMime::QMacPasteboardMime(char t) : type(t)
181 {
182     globalMimeList()->append(this);
183 }
184
185 /*!
186   Destroys a conversion object, removing it from the global
187   list of available convertors.
188 */
189 QMacPasteboardMime::~QMacPasteboardMime()
190 {
191     if(!QApplication::closingDown())
192         globalMimeList()->removeAll(this);
193 }
194
195 class QMacPasteboardMimeAny : public QMacPasteboardMime {
196 private:
197
198 public:
199     QMacPasteboardMimeAny() : QMacPasteboardMime(MIME_QT_CONVERTOR|MIME_ALL) {
200     }
201     ~QMacPasteboardMimeAny() {
202     }
203     QString convertorName();
204
205     QString flavorFor(const QString &mime);
206     QString mimeFor(QString flav);
207     bool canConvert(const QString &mime, QString flav);
208     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
209     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
210 };
211
212 QString QMacPasteboardMimeAny::convertorName()
213 {
214     return QLatin1String("Any-Mime");
215 }
216
217 QString QMacPasteboardMimeAny::flavorFor(const QString &mime)
218 {   
219     // do not handle the mime type name in the drag pasteboard
220     if(mime == QLatin1String("application/x-qt-mime-type-name"))
221         return QString();
222     QString ret = QLatin1String("com.trolltech.anymime.") + mime;
223     return ret.replace(QLatin1Char('/'), QLatin1String("--"));
224 }
225
226 QString QMacPasteboardMimeAny::mimeFor(QString flav)
227 {
228     const QString any_prefix = QLatin1String("com.trolltech.anymime.");
229     if(flav.size() > any_prefix.length() && flav.startsWith(any_prefix))
230         return flav.mid(any_prefix.length()).replace(QLatin1String("--"), QLatin1String("/"));
231     return QString();
232 }
233
234 bool QMacPasteboardMimeAny::canConvert(const QString &mime, QString flav)
235 {
236     return mimeFor(flav) == mime;
237 }
238
239 QVariant QMacPasteboardMimeAny::convertToMime(const QString &mime, QList<QByteArray> data, QString)
240 {
241     if(data.count() > 1)
242         qWarning("QMacPasteboardMimeAny: Cannot handle multiple member data");
243     QVariant ret;
244     if (mime == QLatin1String("text/plain"))
245         ret = QString::fromUtf8(data.first());
246     else
247         ret = data.first();
248     return ret;
249 }
250
251 QList<QByteArray> QMacPasteboardMimeAny::convertFromMime(const QString &mime, QVariant data, QString)
252 {
253     QList<QByteArray> ret;
254     if (mime == QLatin1String("text/plain"))
255         ret.append(data.toString().toUtf8());
256     else
257         ret.append(data.toByteArray());
258     return ret;
259 }
260
261 class QMacPasteboardMimeTypeName : public QMacPasteboardMime {
262 private:
263
264 public:
265     QMacPasteboardMimeTypeName() : QMacPasteboardMime(MIME_QT_CONVERTOR|MIME_ALL) {
266     }
267     ~QMacPasteboardMimeTypeName() {
268     }
269     QString convertorName();
270
271     QString flavorFor(const QString &mime);
272     QString mimeFor(QString flav);
273     bool canConvert(const QString &mime, QString flav);
274     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
275     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
276 };
277
278 QString QMacPasteboardMimeTypeName::convertorName()
279 {
280     return QLatin1String("Qt-Mime-Type");
281 }
282
283 QString QMacPasteboardMimeTypeName::flavorFor(const QString &mime)
284 {
285     if(mime == QLatin1String("application/x-qt-mime-type-name"))
286         return QLatin1String("com.trolltech.qt.MimeTypeName");
287     return QString();
288 }
289
290 QString QMacPasteboardMimeTypeName::mimeFor(QString)
291 {
292     return QString();
293 }
294
295 bool QMacPasteboardMimeTypeName::canConvert(const QString &, QString)
296 {
297     return false;
298 }
299
300 QVariant QMacPasteboardMimeTypeName::convertToMime(const QString &, QList<QByteArray>, QString)
301 {
302     QVariant ret;
303     return ret;
304 }
305
306 QList<QByteArray> QMacPasteboardMimeTypeName::convertFromMime(const QString &, QVariant, QString)
307 {
308     QList<QByteArray> ret;
309     ret.append(QString("x-qt-mime-type-name").toUtf8());
310     return ret;
311 }
312
313 class QMacPasteboardMimePlainText : public QMacPasteboardMime {
314 public:
315     QMacPasteboardMimePlainText() : QMacPasteboardMime(MIME_ALL) { }
316     QString convertorName();
317
318     QString flavorFor(const QString &mime);
319     QString mimeFor(QString flav);
320     bool canConvert(const QString &mime, QString flav);
321     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
322     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
323 };
324
325 QString QMacPasteboardMimePlainText::convertorName()
326 {
327     return QLatin1String("PlainText");
328 }
329
330 QString QMacPasteboardMimePlainText::flavorFor(const QString &mime)
331 {
332     if (mime == QLatin1String("text/plain"))
333         return QLatin1String("com.apple.traditional-mac-plain-text");
334     return QString();
335 }
336
337 QString QMacPasteboardMimePlainText::mimeFor(QString flav)
338 {
339     if (flav == QLatin1String("com.apple.traditional-mac-plain-text"))
340         return QLatin1String("text/plain");
341     return QString();
342 }
343
344 bool QMacPasteboardMimePlainText::canConvert(const QString &mime, QString flav)
345 {
346     return flavorFor(mime) == flav;
347 }
348
349 QVariant QMacPasteboardMimePlainText::convertToMime(const QString &mimetype, QList<QByteArray> data, QString flavor)
350 {
351     if(data.count() > 1)
352         qWarning("QMacPasteboardMimePlainText: Cannot handle multiple member data");
353     const QByteArray &firstData = data.first();
354     QVariant ret;
355     if(flavor == QCFString(QLatin1String("com.apple.traditional-mac-plain-text"))) {
356         QCFString str(CFStringCreateWithBytes(kCFAllocatorDefault,
357                                              reinterpret_cast<const UInt8 *>(firstData.constData()),
358                                              firstData.size(), CFStringGetSystemEncoding(), false));
359         ret = QString(str);
360     } else {
361         qWarning("QMime::convertToMime: unhandled mimetype: %s", qPrintable(mimetype));
362     }
363     return ret;
364 }
365
366 QList<QByteArray> QMacPasteboardMimePlainText::convertFromMime(const QString &, QVariant data, QString flavor)
367 {
368     QList<QByteArray> ret;
369     QString string = data.toString();
370     if(flavor == QCFString(QLatin1String("com.apple.traditional-mac-plain-text")))
371         ret.append(string.toLatin1());
372     return ret;
373 }
374
375 class QMacPasteboardMimeUnicodeText : public QMacPasteboardMime {
376 public:
377     QMacPasteboardMimeUnicodeText() : QMacPasteboardMime(MIME_ALL) { }
378     QString convertorName();
379
380     QString flavorFor(const QString &mime);
381     QString mimeFor(QString flav);
382     bool canConvert(const QString &mime, QString flav);
383     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
384     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
385 };
386
387 QString QMacPasteboardMimeUnicodeText::convertorName()
388 {
389     return QLatin1String("UnicodeText");
390 }
391
392 QString QMacPasteboardMimeUnicodeText::flavorFor(const QString &mime)
393 {
394     if (mime == QLatin1String("text/plain"))
395         return QLatin1String("public.utf16-plain-text");
396     int i = mime.indexOf(QLatin1String("charset="));
397     if (i >= 0) {
398         QString cs(mime.mid(i+8).toLower());
399         i = cs.indexOf(QLatin1Char(';'));
400         if (i>=0)
401             cs = cs.left(i);
402         if (cs == QLatin1String("system"))
403             return QLatin1String("public.utf8-plain-text");
404         else if (cs == QLatin1String("iso-10646-ucs-2")
405                  || cs == QLatin1String("utf16"))
406             return QLatin1String("public.utf16-plain-text");
407     }
408     return QString();
409 }
410
411 QString QMacPasteboardMimeUnicodeText::mimeFor(QString flav)
412 {
413     if (flav == QLatin1String("public.utf16-plain-text") || flav == QLatin1String("public.utf8-plain-text"))
414         return QLatin1String("text/plain");
415     return QString();
416 }
417
418 bool QMacPasteboardMimeUnicodeText::canConvert(const QString &mime, QString flav)
419 {
420     return flavorFor(mime) == flav;
421 }
422
423 QVariant QMacPasteboardMimeUnicodeText::convertToMime(const QString &mimetype, QList<QByteArray> data, QString flavor)
424 {
425     if(data.count() > 1)
426         qWarning("QMacPasteboardMimeUnicodeText: Cannot handle multiple member data");
427     const QByteArray &firstData = data.first();
428     // I can only handle two types (system and unicode) so deal with them that way
429     QVariant ret;
430     if(flavor == QLatin1String("public.utf8-plain-text")) {
431         QCFString str(CFStringCreateWithBytes(kCFAllocatorDefault,
432                                              reinterpret_cast<const UInt8 *>(firstData.constData()),
433                                              firstData.size(), CFStringGetSystemEncoding(), false));
434         ret = QString(str);
435     } else if (flavor == QLatin1String("public.utf16-plain-text")) {
436         ret = QString(reinterpret_cast<const QChar *>(firstData.constData()),
437                       firstData.size() / sizeof(QChar));
438     } else {
439         qWarning("QMime::convertToMime: unhandled mimetype: %s", qPrintable(mimetype));
440     }
441     return ret;
442 }
443
444 QList<QByteArray> QMacPasteboardMimeUnicodeText::convertFromMime(const QString &, QVariant data, QString flavor)
445 {
446     QList<QByteArray> ret;
447     QString string = data.toString();
448     if(flavor == QLatin1String("public.utf8-plain-text"))
449         ret.append(string.toUtf8());
450     else if (flavor == QLatin1String("public.utf16-plain-text"))
451         ret.append(QByteArray((char*)string.utf16(), string.length()*2));
452     return ret;
453 }
454
455 class QMacPasteboardMimeHTMLText : public QMacPasteboardMime {
456 public:
457     QMacPasteboardMimeHTMLText() : QMacPasteboardMime(MIME_ALL) { }
458     QString convertorName();
459
460     QString flavorFor(const QString &mime);
461     QString mimeFor(QString flav);
462     bool canConvert(const QString &mime, QString flav);
463     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
464     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
465 };
466
467 QString QMacPasteboardMimeHTMLText::convertorName()
468 {
469     return QLatin1String("HTML");
470 }
471
472 QString QMacPasteboardMimeHTMLText::flavorFor(const QString &mime)
473 {
474     if (mime == QLatin1String("text/html"))
475         return QLatin1String("public.html");
476     return QString();
477 }
478
479 QString QMacPasteboardMimeHTMLText::mimeFor(QString flav)
480 {
481     if (flav == QLatin1String("public.html"))
482         return QLatin1String("text/html");
483     return QString();
484 }
485
486 bool QMacPasteboardMimeHTMLText::canConvert(const QString &mime, QString flav)
487 {
488     return flavorFor(mime) == flav;
489 }
490
491 QVariant QMacPasteboardMimeHTMLText::convertToMime(const QString &mimeType, QList<QByteArray> data, QString flavor)
492 {
493     if (!canConvert(mimeType, flavor))
494         return QVariant();
495     if (data.count() > 1)
496         qWarning("QMacPasteboardMimeHTMLText: Cannot handle multiple member data");
497     return data.first();
498 }
499
500 QList<QByteArray> QMacPasteboardMimeHTMLText::convertFromMime(const QString &mime, QVariant data, QString flavor)
501 {
502     QList<QByteArray> ret;
503     if (!canConvert(mime, flavor))
504         return ret;
505     ret.append(data.toByteArray());
506     return ret;
507 }
508
509
510 #ifdef Q_WS_MAC32
511
512 // This can be removed once 10.6 is the minimum (or we have to require 64-bit) whichever comes first.
513
514 typedef ComponentResult (*PtrGraphicsImportSetDataHandle)(GraphicsImportComponent, Handle);
515 typedef ComponentResult (*PtrGraphicsImportCreateCGImage)(GraphicsImportComponent, CGImageRef*, UInt32);
516 typedef ComponentResult (*PtrGraphicsExportSetInputCGImage)(GraphicsExportComponent, CGImageRef);
517 typedef ComponentResult (*PtrGraphicsExportSetOutputHandle)(GraphicsExportComponent, Handle);
518 typedef ComponentResult (*PtrGraphicsExportDoExport)(GraphicsExportComponent, unsigned long *);
519
520 static PtrGraphicsImportSetDataHandle ptrGraphicsImportSetDataHandle = 0;
521 static PtrGraphicsImportCreateCGImage ptrGraphicsImportCreateCGImage = 0;
522 static PtrGraphicsExportSetInputCGImage ptrGraphicsExportSetInputCGImage = 0;
523 static PtrGraphicsExportSetOutputHandle ptrGraphicsExportSetOutputHandle = 0;
524 static PtrGraphicsExportDoExport ptrGraphicsExportDoExport = 0;
525
526 static bool resolveMimeQuickTimeSymbols()
527 {
528     if (ptrGraphicsImportSetDataHandle == 0) {
529         QLibrary library(QLatin1String("/System/Library/Frameworks/QuickTime.framework/QuickTime"));
530         ptrGraphicsImportSetDataHandle = reinterpret_cast<PtrGraphicsImportSetDataHandle>(library.resolve("GraphicsImportSetDataHandle"));
531         ptrGraphicsImportCreateCGImage = reinterpret_cast<PtrGraphicsImportCreateCGImage>(library.resolve("GraphicsImportCreateCGImage"));
532         ptrGraphicsExportSetInputCGImage = reinterpret_cast<PtrGraphicsExportSetInputCGImage>(library.resolve("GraphicsExportSetInputCGImage"));
533         ptrGraphicsExportSetOutputHandle = reinterpret_cast<PtrGraphicsExportSetOutputHandle>(library.resolve("GraphicsExportSetOutputHandle"));
534         ptrGraphicsExportDoExport = reinterpret_cast<PtrGraphicsExportDoExport>(library.resolve("GraphicsExportDoExport"));
535     }
536
537     return ptrGraphicsImportSetDataHandle != 0
538            && ptrGraphicsImportCreateCGImage != 0 && ptrGraphicsExportSetInputCGImage != 0
539            && ptrGraphicsExportSetOutputHandle != 0 && ptrGraphicsExportDoExport != 0;
540 }
541
542 class QMacPasteboardMimePict : public QMacPasteboardMime {
543 public:
544     QMacPasteboardMimePict() : QMacPasteboardMime(MIME_ALL) { }
545     QString convertorName();
546
547     QString flavorFor(const QString &mime);
548     QString mimeFor(QString flav);
549     bool canConvert(const QString &mime, QString flav);
550     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
551     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
552 };
553
554 QString QMacPasteboardMimePict::convertorName()
555 {
556     return QLatin1String("Pict");
557 }
558
559 QString QMacPasteboardMimePict::flavorFor(const QString &mime)
560 {
561     if(mime.startsWith(QLatin1String("application/x-qt-image")))
562         return QLatin1String("com.apple.pict");
563     return QString();
564 }
565
566 QString QMacPasteboardMimePict::mimeFor(QString flav)
567 {
568     if(flav == QLatin1String("com.apple.pict"))
569         return QLatin1String("application/x-qt-image");
570     return QString();
571 }
572
573 bool QMacPasteboardMimePict::canConvert(const QString &mime, QString flav)
574 {
575     return flav == QLatin1String("com.apple.pict")
576             && mime == QLatin1String("application/x-qt-image");
577 }
578
579
580 QVariant QMacPasteboardMimePict::convertToMime(const QString &mime, QList<QByteArray> data, QString flav)
581 {
582     if(data.count() > 1)
583         qWarning("QMacPasteboardMimePict: Cannot handle multiple member data");
584     QVariant ret;
585     if (!resolveMimeQuickTimeSymbols())
586         return ret;
587
588     if(!canConvert(mime, flav))
589         return ret;
590     const QByteArray &a = data.first();
591
592     // This function expects the 512 header (just to skip it, so create the extra space for it).
593     Handle pic = NewHandle(a.size() + 512);
594     memcpy(*pic + 512, a.constData(), a.size());
595
596     GraphicsImportComponent graphicsImporter;
597     ComponentResult result = OpenADefaultComponent(GraphicsImporterComponentType,
598                                                    kQTFileTypePicture, &graphicsImporter);
599     QCFType<CGImageRef> cgImage;
600     if (!result)
601         result = ptrGraphicsImportSetDataHandle(graphicsImporter, pic);
602     if (!result)
603         result = ptrGraphicsImportCreateCGImage(graphicsImporter, &cgImage,
604                                              kGraphicsImportCreateCGImageUsingCurrentSettings);
605     if (!result)
606         ret = QVariant(QPixmap::fromMacCGImageRef(cgImage).toImage());
607     CloseComponent(graphicsImporter);
608     DisposeHandle(pic);
609     return ret;
610 }
611
612 QList<QByteArray> QMacPasteboardMimePict::convertFromMime(const QString &mime, QVariant variant,
613                                                           QString flav)
614 {
615     QList<QByteArray> ret;
616     if (!resolveMimeQuickTimeSymbols())
617         return ret;
618
619     if (!canConvert(mime, flav))
620         return ret;
621     QCFType<CGImageRef> cgimage = qt_mac_createCGImageFromQImage(qvariant_cast<QImage>(variant));
622     Handle pic = NewHandle(0);
623     GraphicsExportComponent graphicsExporter;
624     ComponentResult result = OpenADefaultComponent(GraphicsExporterComponentType,
625                                                    kQTFileTypePicture, &graphicsExporter);
626     if (!result) {
627         unsigned long sizeWritten;
628         result = ptrGraphicsExportSetInputCGImage(graphicsExporter, cgimage);
629         if (!result)
630             result = ptrGraphicsExportSetOutputHandle(graphicsExporter, pic);
631         if (!result)
632             result = ptrGraphicsExportDoExport(graphicsExporter, &sizeWritten);
633
634         CloseComponent(graphicsExporter);
635     }
636
637     int size = GetHandleSize((Handle)pic);
638     // Skip the Picture File header (512 bytes) and feed the raw data
639     QByteArray ar(reinterpret_cast<char *>(*pic + 512), size - 512);
640     ret.append(ar);
641     DisposeHandle(pic);
642     return ret;
643 }
644
645
646 #endif //Q_WS_MAC32
647
648 class QMacPasteboardMimeTiff : public QMacPasteboardMime {
649 public:
650     QMacPasteboardMimeTiff() : QMacPasteboardMime(MIME_ALL) { }
651     QString convertorName();
652
653     QString flavorFor(const QString &mime);
654     QString mimeFor(QString flav);
655     bool canConvert(const QString &mime, QString flav);
656     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
657     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
658 };
659
660 QString QMacPasteboardMimeTiff::convertorName()
661 {
662     return QLatin1String("Tiff");
663 }
664
665 QString QMacPasteboardMimeTiff::flavorFor(const QString &mime)
666 {
667     if(mime.startsWith(QLatin1String("application/x-qt-image")))
668         return QLatin1String("public.tiff");
669     return QString();
670 }
671
672 QString QMacPasteboardMimeTiff::mimeFor(QString flav)
673 {
674     if(flav == QLatin1String("public.tiff"))
675         return QLatin1String("application/x-qt-image");
676     return QString();
677 }
678
679 bool QMacPasteboardMimeTiff::canConvert(const QString &mime, QString flav)
680 {
681     return flav == QLatin1String("public.tiff") && mime == QLatin1String("application/x-qt-image");
682 }
683
684 QVariant QMacPasteboardMimeTiff::convertToMime(const QString &mime, QList<QByteArray> data, QString flav)
685 {
686     if(data.count() > 1)
687         qWarning("QMacPasteboardMimeTiff: Cannot handle multiple member data");
688     QVariant ret;
689     if (!canConvert(mime, flav))
690         return ret;
691     const QByteArray &a = data.first();
692     QCFType<CGImageRef> image;
693     QCFType<CFDataRef> tiffData = CFDataCreateWithBytesNoCopy(0,
694                                                 reinterpret_cast<const UInt8 *>(a.constData()),
695                                                 a.size(), kCFAllocatorNull);
696     QCFType<CGImageSourceRef> imageSource = CGImageSourceCreateWithData(tiffData, 0);
697     image = CGImageSourceCreateImageAtIndex(imageSource, 0, 0);
698
699     if (image != 0)
700         ret = QVariant(QPixmap::fromMacCGImageRef(image).toImage());
701     return ret;
702 }
703
704 QList<QByteArray> QMacPasteboardMimeTiff::convertFromMime(const QString &mime, QVariant variant, QString flav)
705 {
706     QList<QByteArray> ret;
707     if (!canConvert(mime, flav))
708         return ret;
709
710     QImage img = qvariant_cast<QImage>(variant);
711     QCFType<CGImageRef> cgimage = qt_mac_createCGImageFromQImage(img);
712 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
713     if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
714         QCFType<CFMutableDataRef> data = CFDataCreateMutable(0, 0);
715         QCFType<CGImageDestinationRef> imageDestination = CGImageDestinationCreateWithData(data, kUTTypeTIFF, 1, 0);
716         if (imageDestination != 0) {
717             CFTypeRef keys[2];
718             QCFType<CFTypeRef> values[2];
719             QCFType<CFDictionaryRef> options;
720             keys[0] = kCGImagePropertyPixelWidth;
721             keys[1] = kCGImagePropertyPixelHeight;
722             int width = img.width();
723             int height = img.height();
724             values[0] = CFNumberCreate(0, kCFNumberIntType, &width);
725             values[1] = CFNumberCreate(0, kCFNumberIntType, &height);
726             options = CFDictionaryCreate(0, reinterpret_cast<const void **>(keys),
727                                          reinterpret_cast<const void **>(values), 2,
728                                          &kCFTypeDictionaryKeyCallBacks,
729                                          &kCFTypeDictionaryValueCallBacks);
730             CGImageDestinationAddImage(imageDestination, cgimage, options);
731             CGImageDestinationFinalize(imageDestination);
732         }
733         QByteArray ar(CFDataGetLength(data), 0);
734         CFDataGetBytes(data,
735                 CFRangeMake(0, ar.size()),
736                 reinterpret_cast<UInt8 *>(ar.data()));
737         ret.append(ar);
738     } else
739 #endif
740     {
741 #ifdef Q_WS_MAC32
742         Handle tiff = NewHandle(0);
743         if (resolveMimeQuickTimeSymbols()) {
744             GraphicsExportComponent graphicsExporter;
745             ComponentResult result = OpenADefaultComponent(GraphicsExporterComponentType,
746                                                            kQTFileTypeTIFF, &graphicsExporter);
747             if (!result) {
748                 unsigned long sizeWritten;
749                 result = ptrGraphicsExportSetInputCGImage(graphicsExporter, cgimage);
750                 if (!result)
751                     result = ptrGraphicsExportSetOutputHandle(graphicsExporter, tiff);
752                 if (!result)
753                     result = ptrGraphicsExportDoExport(graphicsExporter, &sizeWritten);
754
755                 CloseComponent(graphicsExporter);
756             }
757         }
758         int size = GetHandleSize((Handle)tiff);
759         QByteArray ar(reinterpret_cast<char *>(*tiff), size);
760         ret.append(ar);
761         DisposeHandle(tiff);
762 #endif
763     }
764     return ret;
765 }
766
767
768 class QMacPasteboardMimeFileUri : public QMacPasteboardMime {
769 public:
770     QMacPasteboardMimeFileUri() : QMacPasteboardMime(MIME_ALL) { }
771     QString convertorName();
772
773     QString flavorFor(const QString &mime);
774     QString mimeFor(QString flav);
775     bool canConvert(const QString &mime, QString flav);
776     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
777     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
778 };
779
780 QString QMacPasteboardMimeFileUri::convertorName()
781 {
782     return QLatin1String("FileURL");
783 }
784
785 QString QMacPasteboardMimeFileUri::flavorFor(const QString &mime)
786 {
787     if (mime == QLatin1String("text/uri-list"))
788         return QCFString(UTTypeCreatePreferredIdentifierForTag(kUTTagClassOSType, CFSTR("furl"), 0));
789     return QString();
790 }
791
792 QString QMacPasteboardMimeFileUri::mimeFor(QString flav)
793 {
794     if (flav == QCFString(UTTypeCreatePreferredIdentifierForTag(kUTTagClassOSType, CFSTR("furl"), 0)))
795         return QLatin1String("text/uri-list");
796     return QString();
797 }
798
799 bool QMacPasteboardMimeFileUri::canConvert(const QString &mime, QString flav)
800 {
801     return mime == QLatin1String("text/uri-list")
802             && flav == QCFString(UTTypeCreatePreferredIdentifierForTag(kUTTagClassOSType, CFSTR("furl"), 0));
803 }
804
805 QVariant QMacPasteboardMimeFileUri::convertToMime(const QString &mime, QList<QByteArray> data, QString flav)
806 {
807     if(!canConvert(mime, flav))
808         return QVariant();
809     QList<QVariant> ret;
810     for(int i = 0; i < data.size(); ++i) {
811         QUrl url = QUrl::fromEncoded(data.at(i));
812         if (url.host().toLower() == QLatin1String("localhost"))
813             url.setHost(QString());
814         url.setPath(url.path().normalized(QString::NormalizationForm_C));
815         ret.append(url);
816     }
817     return QVariant(ret);
818 }
819
820 QList<QByteArray> QMacPasteboardMimeFileUri::convertFromMime(const QString &mime, QVariant data, QString flav)
821 {
822     QList<QByteArray> ret;
823     if (!canConvert(mime, flav))
824         return ret;
825     QList<QVariant> urls = data.toList();
826     for(int i = 0; i < urls.size(); ++i) {
827         QUrl url = urls.at(i).toUrl();
828         if (url.scheme().isEmpty())
829             url.setScheme(QLatin1String("file"));
830         if (url.scheme().toLower() == QLatin1String("file")) {
831             if (url.host().isEmpty())
832                 url.setHost(QLatin1String("localhost"));
833             url.setPath(url.path().normalized(QString::NormalizationForm_D));
834         }
835         ret.append(url.toEncoded());
836     }
837     return ret;
838 }
839
840 class QMacPasteboardMimeUrl : public QMacPasteboardMime {
841 public:
842     QMacPasteboardMimeUrl() : QMacPasteboardMime(MIME_ALL) { }
843     QString convertorName();
844
845     QString flavorFor(const QString &mime);
846     QString mimeFor(QString flav);
847     bool canConvert(const QString &mime, QString flav);
848     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
849     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
850 };
851
852 QString QMacPasteboardMimeUrl::convertorName()
853 {
854     return QLatin1String("URL");
855 }
856
857 QString QMacPasteboardMimeUrl::flavorFor(const QString &mime)
858 {
859     if(mime.startsWith(QLatin1String("text/uri-list")))
860         return QLatin1String("public.url");
861     return QString();
862 }
863
864 QString QMacPasteboardMimeUrl::mimeFor(QString flav)
865 {
866     if(flav == QLatin1String("public.url"))
867         return QLatin1String("text/uri-list");
868     return QString();
869 }
870
871 bool QMacPasteboardMimeUrl::canConvert(const QString &mime, QString flav)
872 {
873     return flav == QLatin1String("public.url")
874             && mime == QLatin1String("text/uri-list");
875 }
876
877 QVariant QMacPasteboardMimeUrl::convertToMime(const QString &mime, QList<QByteArray> data, QString flav)
878 {
879     if(!canConvert(mime, flav))
880         return QVariant();
881
882     QList<QVariant> ret;
883     for (int i=0; i<data.size(); ++i) {
884         QUrl url = QUrl::fromEncoded(data.at(i));
885         if (url.host().toLower() == QLatin1String("localhost"))
886             url.setHost(QString());
887         url.setPath(url.path().normalized(QString::NormalizationForm_C));
888         ret.append(url);
889     }
890     return QVariant(ret);
891 }
892
893 QList<QByteArray> QMacPasteboardMimeUrl::convertFromMime(const QString &mime, QVariant data, QString flav)
894 {
895     QList<QByteArray> ret;
896     if (!canConvert(mime, flav))
897         return ret;
898
899     QList<QVariant> urls = data.toList();
900     for(int i=0; i<urls.size(); ++i) {
901         QUrl url = urls.at(i).toUrl();
902         if (url.scheme().isEmpty())
903             url.setScheme(QLatin1String("file"));
904         if (url.scheme().toLower() == QLatin1String("file")) {
905             if (url.host().isEmpty())
906                 url.setHost(QLatin1String("localhost"));
907             url.setPath(url.path().normalized(QString::NormalizationForm_D));
908         }
909         ret.append(url.toEncoded());
910     }
911     return ret;
912 }
913
914 class QMacPasteboardMimeVCard : public QMacPasteboardMime
915 {
916 public:
917     QMacPasteboardMimeVCard() : QMacPasteboardMime(MIME_ALL){ }
918     QString convertorName();
919
920     QString flavorFor(const QString &mime);
921     QString mimeFor(QString flav);
922     bool canConvert(const QString &mime, QString flav);
923     QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
924     QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
925 };
926
927 QString QMacPasteboardMimeVCard::convertorName()
928 {
929     return QString("VCard");
930 }
931
932 bool QMacPasteboardMimeVCard::canConvert(const QString &mime, QString flav)
933 {
934     return mimeFor(flav) == mime;
935 }
936
937 QString QMacPasteboardMimeVCard::flavorFor(const QString &mime)
938 {
939     if(mime.startsWith(QLatin1String("text/plain")))
940         return QLatin1String("public.vcard");
941     return QString();
942 }
943
944 QString QMacPasteboardMimeVCard::mimeFor(QString flav)
945 {
946     if (flav == QLatin1String("public.vcard"))
947         return QLatin1String("text/plain");
948     return QString();
949 }
950
951 QVariant QMacPasteboardMimeVCard::convertToMime(const QString &mime, QList<QByteArray> data, QString)
952 {
953     QByteArray cards;
954     if (mime == QLatin1String("text/plain")) {
955         for (int i=0; i<data.size(); ++i)
956             cards += data[i];
957     }
958     return QVariant(cards);
959 }
960
961 QList<QByteArray> QMacPasteboardMimeVCard::convertFromMime(const QString &mime, QVariant data, QString)
962 {
963     QList<QByteArray> ret;
964     if (mime == QLatin1String("text/plain"))
965         ret.append(data.toString().toUtf8());
966     return ret;
967 }
968
969
970 /*!
971   \internal
972
973   This is an internal function.
974 */
975 void QMacPasteboardMime::initialize()
976 {
977     if(globalMimeList()->isEmpty()) {
978         qAddPostRoutine(cleanup_mimes);
979
980         //standard types that we wrap
981         new QMacPasteboardMimeTiff;
982 #ifdef Q_WS_MAC32
983         // 10.6 does automatic synthesis to and from PICT to standard image types (like TIFF),
984         // so don't bother doing it ourselves, especially since it's not available in 64-bit.
985         if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_6)
986             new QMacPasteboardMimePict;
987 #endif
988         new QMacPasteboardMimeUnicodeText;
989         new QMacPasteboardMimePlainText;
990         new QMacPasteboardMimeHTMLText;
991         new QMacPasteboardMimeFileUri;
992         new QMacPasteboardMimeUrl;
993         new QMacPasteboardMimeTypeName;
994         new QMacPasteboardMimeVCard;
995         //make sure our "non-standard" types are always last! --Sam
996         new QMacPasteboardMimeAny;
997     }
998 }
999
1000 /*!
1001   Returns the most-recently created QMacPasteboardMime of type \a t that can convert
1002   between the \a mime and \a flav formats.  Returns 0 if no such convertor
1003   exists.
1004 */
1005 QMacPasteboardMime*
1006 QMacPasteboardMime::convertor(uchar t, const QString &mime, QString flav)
1007 {
1008     MimeList *mimes = globalMimeList();
1009     for(MimeList::const_iterator it = mimes->constBegin(); it != mimes->constEnd(); ++it) {
1010 #ifdef DEBUG_MIME_MAPS
1011         qDebug("QMacPasteboardMime::convertor: seeing if %s (%d) can convert %s to %d[%c%c%c%c] [%d]",
1012                (*it)->convertorName().toLatin1().constData(),
1013                (*it)->type & t, mime.toLatin1().constData(),
1014                flav, (flav >> 24) & 0xFF, (flav >> 16) & 0xFF, (flav >> 8) & 0xFF, (flav) & 0xFF,
1015                (*it)->canConvert(mime,flav));
1016         for(int i = 0; i < (*it)->countFlavors(); ++i) {
1017             int f = (*it)->flavor(i);
1018             qDebug("  %d) %d[%c%c%c%c] [%s]", i, f,
1019                    (f >> 24) & 0xFF, (f >> 16) & 0xFF, (f >> 8) & 0xFF, (f) & 0xFF,
1020                    (*it)->convertorName().toLatin1().constData());
1021         }
1022 #endif
1023         if(((*it)->type & t) && (*it)->canConvert(mime, flav))
1024             return (*it);
1025     }
1026     return 0;
1027 }
1028 /*!
1029   Returns a MIME type of type \a t for \a flav, or 0 if none exists.
1030 */
1031 QString QMacPasteboardMime::flavorToMime(uchar t, QString flav)
1032 {
1033     MimeList *mimes = globalMimeList();
1034     for(MimeList::const_iterator it = mimes->constBegin(); it != mimes->constEnd(); ++it) {
1035 #ifdef DEBUG_MIME_MAPS
1036         qDebug("QMacMIme::flavorToMime: attempting %s (%d) for flavor %d[%c%c%c%c] [%s]",
1037                (*it)->convertorName().toLatin1().constData(),
1038                (*it)->type & t, flav, (flav >> 24) & 0xFF, (flav >> 16) & 0xFF, (flav >> 8) & 0xFF, (flav) & 0xFF,
1039                (*it)->mimeFor(flav).toLatin1().constData());
1040
1041 #endif
1042         if((*it)->type & t) {
1043             QString mimeType = (*it)->mimeFor(flav);
1044             if(!mimeType.isNull())
1045                 return mimeType;
1046         }
1047     }
1048     return QString();
1049 }
1050
1051 /*!
1052   Returns a list of all currently defined QMacPasteboardMime objects of type \a t.
1053 */
1054 QList<QMacPasteboardMime*> QMacPasteboardMime::all(uchar t)
1055 {
1056     MimeList ret;
1057     MimeList *mimes = globalMimeList();
1058     for(MimeList::const_iterator it = mimes->constBegin(); it != mimes->constEnd(); ++it) {
1059         if((*it)->type & t)
1060             ret.append((*it));
1061     }
1062     return ret;
1063 }
1064
1065
1066 /*!
1067   \fn QString QMacPasteboardMime::convertorName()
1068
1069   Returns a name for the convertor.
1070
1071   All subclasses must reimplement this pure virtual function.
1072 */
1073
1074 /*!
1075   \fn bool QMacPasteboardMime::canConvert(const QString &mime, QString flav)
1076
1077   Returns true if the convertor can convert (both ways) between
1078   \a mime and \a flav; otherwise returns false.
1079
1080   All subclasses must reimplement this pure virtual function.
1081 */
1082
1083 /*!
1084   \fn QString QMacPasteboardMime::mimeFor(QString flav)
1085
1086   Returns the MIME UTI used for Mac flavor \a flav, or 0 if this
1087   convertor does not support \a flav.
1088
1089   All subclasses must reimplement this pure virtual function.
1090 */
1091
1092 /*!
1093   \fn QString QMacPasteboardMime::flavorFor(const QString &mime)
1094
1095   Returns the Mac UTI used for MIME type \a mime, or 0 if this
1096   convertor does not support \a mime.
1097
1098   All subclasses must reimplement this pure virtual function.
1099 */
1100
1101 /*!
1102     \fn QVariant QMacPasteboardMime::convertToMime(const QString &mime, QList<QByteArray> data, QString flav)
1103
1104     Returns \a data converted from Mac UTI \a flav to MIME type \a
1105     mime.
1106
1107     Note that Mac flavors must all be self-terminating. The input \a
1108     data may contain trailing data.
1109
1110     All subclasses must reimplement this pure virtual function.
1111 */
1112
1113 /*!
1114   \fn QList<QByteArray> QMacPasteboardMime::convertFromMime(const QString &mime, QVariant data, QString flav)
1115
1116   Returns \a data converted from MIME type \a mime
1117     to Mac UTI \a flav.
1118
1119   Note that Mac flavors must all be self-terminating.  The return
1120   value may contain trailing data.
1121
1122   All subclasses must reimplement this pure virtual function.
1123 */
1124
1125
1126 QT_END_NAMESPACE