source: trunk/src/gui/kernel/qmime_mac.cpp@ 477

Last change on this file since 477 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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