Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / osx / DataFlavorMapping.cxx
blob012889abfb609066d378e1cd2d7f29f317e42443
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sal/config.h"
22 #include <DataFlavorMapping.hxx>
23 #include "HtmlFmtFlt.hxx"
24 #include "PictToBmpFlt.hxx"
25 #include "com/sun/star/datatransfer/UnsupportedFlavorException.hpp"
26 #include "com/sun/star/datatransfer/XMimeContentType.hpp"
27 #include "com/sun/star/datatransfer/MimeContentTypeFactory.hpp"
28 #include "com/sun/star/lang/IllegalArgumentException.hpp"
29 #include "com/sun/star/uno/Sequence.hxx"
30 #include "comphelper/processfactory.hxx"
32 #include <rtl/ustring.hxx>
33 #include <osl/endian.h>
35 #include <cassert>
36 #include <string.h>
38 #include <premac.h>
39 #include <Cocoa/Cocoa.h>
40 #include <postmac.h>
42 using namespace ::com::sun::star::datatransfer;
43 using namespace ::com::sun::star::uno;
44 using namespace com::sun::star::lang;
45 using namespace cppu;
46 using namespace std;
48 namespace
50 /* Determine whether or not a DataFlavor is valid.
52 bool isValidFlavor(const DataFlavor& aFlavor)
54 size_t len = aFlavor.MimeType.getLength();
55 Type dtype = aFlavor.DataType;
56 return ((len > 0) && ((dtype == cppu::UnoType<Sequence<sal_Int8>>::get()) || (dtype == cppu::UnoType<OUString>::get())));
59 OUString NSStringToOUString( const NSString* cfString)
61 assert(cfString && "Invalid parameter");
63 const char* utf8Str = [cfString UTF8String];
64 unsigned int len = rtl_str_getLength(utf8Str);
66 return OUString(utf8Str, len, RTL_TEXTENCODING_UTF8);
69 NSString* OUStringToNSString(const OUString& ustring)
71 OString utf8Str = OUStringToOString(ustring, RTL_TEXTENCODING_UTF8);
72 return [NSString stringWithCString: utf8Str.getStr() encoding: NSUTF8StringEncoding];
75 NSString* PBTYPE_SODX = @"application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"";
76 NSString* PBTYPE_SESX = @"application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
77 NSString* PBTYPE_SLSDX = @"application/x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link Source Descriptor (XML)\"";
78 NSString* PBTYPE_ESX = @"application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
79 NSString* PBTYPE_LSX = @"application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\"";
80 NSString* PBTYPE_EOX = @"application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star Embedded Object (XML)\"";
81 NSString* PBTYPE_SVXB = @"application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\"";
82 NSString* PBTYPE_GDIMF = @"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
83 NSString* PBTYPE_WMF = @"application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
84 NSString* PBTYPE_EMF = @"application/x-openoffice-emf;windows_formatname=\"Image EMF\"";
86 NSString* PBTYPE_DUMMY_INTERNAL = @"application/x-openoffice-internal";
88 const char* FLAVOR_SODX = "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"";
89 const char* FLAVOR_SESX = "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
90 const char* FLAVOR_SLSDX = "application/x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link Source Descriptor (XML)\"";
91 const char* FLAVOR_ESX = "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
92 const char* FLAVOR_LSX = "application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\"";
93 const char* FLAVOR_EOX = "application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star Embedded Object (XML)\"";
94 const char* FLAVOR_SVXB = "application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\"";
95 const char* FLAVOR_GDIMF = "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
96 const char* FLAVOR_WMF = "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
97 const char* FLAVOR_EMF = "application/x-openoffice-emf;windows_formatname=\"Image EMF\"";
99 const char* FLAVOR_DUMMY_INTERNAL = "application/x-openoffice-internal";
101 struct FlavorMap
103 const NSString* SystemFlavor;
104 const char* OOoFlavor;
105 const char* HumanPresentableName;
106 bool DataTypeOUString; // sequence<byte> otherwise
109 /* At the moment it appears as if only MS Office pastes "public.html" to the clipboard.
111 static const FlavorMap flavorMap[] =
113 { NSStringPboardType, "text/plain;charset=utf-16", "Unicode Text (UTF-16)", true },
114 { NSRTFPboardType, "text/rtf", "Rich Text Format", false },
115 { NSTIFFPboardType, "image/png", "Portable Network Graphics", false },
116 { NSHTMLPboardType, "text/html", "Plain Html", false },
117 { NSFilenamesPboardType, "application/x-openoffice-filelist;windows_formatname=\"FileList\"", "FileList", false },
118 { PBTYPE_SESX, FLAVOR_SESX, "Star Embed Source (XML)", false },
119 { PBTYPE_SLSDX, FLAVOR_SLSDX, "Star Link Source Descriptor (XML)", false },
120 { PBTYPE_ESX, FLAVOR_ESX, "Star Embed Source (XML)", false },
121 { PBTYPE_LSX, FLAVOR_LSX, "Star Link Source (XML)", false },
122 { PBTYPE_EOX, FLAVOR_EOX, "Star Embedded Object (XML)", false },
123 { PBTYPE_SVXB, FLAVOR_SVXB, "SVXB (StarView Bitmap/Animation", false },
124 { PBTYPE_GDIMF, FLAVOR_GDIMF, "GDIMetaFile", false },
125 { PBTYPE_WMF, FLAVOR_WMF, "Windows MetaFile", false },
126 { PBTYPE_EMF, FLAVOR_EMF, "Windows Enhanced MetaFile", false },
127 { PBTYPE_SODX, FLAVOR_SODX, "Star Object Descriptor (XML)", false },
128 { PBTYPE_DUMMY_INTERNAL, FLAVOR_DUMMY_INTERNAL, "internal data",false }
131 #define SIZE_FLAVOR_MAP (sizeof(flavorMap)/sizeof(FlavorMap))
133 inline bool isByteSequenceType(const Type& theType)
135 return (theType == cppu::UnoType<Sequence<sal_Int8>>::get());
138 inline bool isOUStringType(const Type& theType)
140 return (theType == cppu::UnoType<OUString>::get() );
143 } // unnamed namespace
145 /* A base class for other data provider.
147 class DataProviderBaseImpl : public DataProvider
149 public:
150 DataProviderBaseImpl(const Any& data);
151 DataProviderBaseImpl(id data);
152 virtual ~DataProviderBaseImpl() override;
154 protected:
155 Any mData;
156 //NSData* mSystemData;
157 id mSystemData;
160 DataProviderBaseImpl::DataProviderBaseImpl(const Any& data) :
161 mData(data),
162 mSystemData(nil)
166 DataProviderBaseImpl::DataProviderBaseImpl(id data) :
167 mSystemData(data)
169 [mSystemData retain];
172 DataProviderBaseImpl::~DataProviderBaseImpl()
174 if (mSystemData)
176 [mSystemData release];
180 class UniDataProvider : public DataProviderBaseImpl
182 public:
183 UniDataProvider(const Any& data);
185 UniDataProvider(NSData* data);
187 virtual NSData* getSystemData() override;
189 virtual Any getOOoData() override;
192 UniDataProvider::UniDataProvider(const Any& data) :
193 DataProviderBaseImpl(data)
197 UniDataProvider::UniDataProvider(NSData* data) :
198 DataProviderBaseImpl(data)
202 NSData* UniDataProvider::getSystemData()
204 OUString ustr;
205 mData >>= ustr;
207 OString strUtf8;
208 ustr.convertToString(&strUtf8, RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS);
210 return [NSData dataWithBytes: strUtf8.getStr() length: strUtf8.getLength()];
213 Any UniDataProvider::getOOoData()
215 Any oOOData;
217 if (mSystemData)
219 oOOData <<= OUString(static_cast<const sal_Char*>([mSystemData bytes]),
220 [mSystemData length],
221 RTL_TEXTENCODING_UTF8);
223 else
225 oOOData = mData;
228 return oOOData;
231 class ByteSequenceDataProvider : public DataProviderBaseImpl
233 public:
234 ByteSequenceDataProvider(const Any& data);
236 ByteSequenceDataProvider(NSData* data);
238 virtual NSData* getSystemData() override;
240 virtual Any getOOoData() override;
243 ByteSequenceDataProvider::ByteSequenceDataProvider(const Any& data) :
244 DataProviderBaseImpl(data)
248 ByteSequenceDataProvider::ByteSequenceDataProvider(NSData* data) :
249 DataProviderBaseImpl(data)
253 NSData* ByteSequenceDataProvider::getSystemData()
255 Sequence<sal_Int8> rawData;
256 mData >>= rawData;
258 return [NSData dataWithBytes: rawData.getArray() length: rawData.getLength()];
261 Any ByteSequenceDataProvider::getOOoData()
263 Any oOOData;
265 if (mSystemData)
267 unsigned int flavorDataLength = [mSystemData length];
268 Sequence<sal_Int8> byteSequence;
269 byteSequence.realloc(flavorDataLength);
270 memcpy(byteSequence.getArray(), [mSystemData bytes], flavorDataLength);
271 oOOData <<= byteSequence;
273 else
275 oOOData = mData;
278 return oOOData;
281 class HTMLFormatDataProvider : public DataProviderBaseImpl
283 public:
284 HTMLFormatDataProvider(NSData* data);
286 virtual NSData* getSystemData() override;
288 virtual Any getOOoData() override;
291 HTMLFormatDataProvider::HTMLFormatDataProvider(NSData* data) :
292 DataProviderBaseImpl(data)
296 NSData* HTMLFormatDataProvider::getSystemData()
298 Sequence<sal_Int8> textHtmlData;
299 mData >>= textHtmlData;
301 Sequence<sal_Int8> htmlFormatData = TextHtmlToHTMLFormat(textHtmlData);
303 return [NSData dataWithBytes: htmlFormatData.getArray() length: htmlFormatData.getLength()];
306 Any HTMLFormatDataProvider::getOOoData()
308 Any oOOData;
310 if (mSystemData)
312 unsigned int flavorDataLength = [mSystemData length];
313 Sequence<sal_Int8> unkHtmlData;
315 unkHtmlData.realloc(flavorDataLength);
316 memcpy(unkHtmlData.getArray(), [mSystemData bytes], flavorDataLength);
318 Sequence<sal_Int8>* pPlainHtml = &unkHtmlData;
319 Sequence<sal_Int8> plainHtml;
321 if (isHTMLFormat(unkHtmlData))
323 plainHtml = HTMLFormatToTextHtml(unkHtmlData);
324 pPlainHtml = &plainHtml;
327 oOOData <<= *pPlainHtml;
329 else
331 oOOData = mData;
334 return oOOData;
337 class PNGDataProvider : public DataProviderBaseImpl
339 NSBitmapImageFileType meImageType;
340 public:
341 PNGDataProvider( const Any&, NSBitmapImageFileType);
343 PNGDataProvider( NSData*, NSBitmapImageFileType);
345 virtual NSData* getSystemData() override;
347 virtual Any getOOoData() override;
350 PNGDataProvider::PNGDataProvider( const Any& data, NSBitmapImageFileType eImageType) :
351 DataProviderBaseImpl(data),
352 meImageType( eImageType )
356 PNGDataProvider::PNGDataProvider( NSData* data, NSBitmapImageFileType eImageType) :
357 DataProviderBaseImpl(data),
358 meImageType( eImageType )
362 NSData* PNGDataProvider::getSystemData()
364 Sequence<sal_Int8> pngData;
365 mData >>= pngData;
367 Sequence<sal_Int8> imgData;
368 NSData* sysData = nullptr;
369 if( PNGToImage( pngData, imgData, meImageType))
370 sysData = [NSData dataWithBytes: imgData.getArray() length: imgData.getLength()];
372 return sysData;
375 /* The AOO 'PCT' filter is not yet good enough to be used
376 and there is no flavor defined for exchanging 'PCT' with AOO
377 so we convert 'PCT' to a PNG and provide this to AOO
379 Any PNGDataProvider::getOOoData()
381 Any oOOData;
383 if( mSystemData)
385 const unsigned int flavorDataLength = [mSystemData length];
386 Sequence<sal_Int8> imgData( flavorDataLength);
387 memcpy( imgData.getArray(), [mSystemData bytes], flavorDataLength);
389 Sequence<sal_Int8> pngData;
390 if( ImageToPNG( imgData, pngData, meImageType))
391 oOOData <<= pngData;
393 else
395 oOOData = mData;
398 return oOOData;
401 class FileListDataProvider : public DataProviderBaseImpl
403 public:
404 FileListDataProvider(const Any& data);
405 FileListDataProvider(NSArray* data);
407 virtual NSData* getSystemData() override;
408 virtual Any getOOoData() override;
411 FileListDataProvider::FileListDataProvider(const Any& data) :
412 DataProviderBaseImpl(data)
416 FileListDataProvider::FileListDataProvider(NSArray* data) :
417 DataProviderBaseImpl(data)
421 NSData* FileListDataProvider::getSystemData()
423 return [NSData data];
426 Any FileListDataProvider::getOOoData()
428 Any oOOData;
430 if (mSystemData)
432 size_t length = [mSystemData count];
433 size_t lenSeqRequired = 0;
435 for (size_t i = 0; i < length; i++)
437 NSString* fname = [mSystemData objectAtIndex: i];
438 lenSeqRequired += [fname maximumLengthOfBytesUsingEncoding: NSUnicodeStringEncoding] + sizeof(unichar);
441 Sequence<sal_Int8> oOOFileList(lenSeqRequired);
442 unichar* pBuffer = reinterpret_cast<unichar*>(oOOFileList.getArray());
443 memset(pBuffer, 0, lenSeqRequired);
445 for (size_t i = 0; i < length; i++)
447 NSString* fname = [mSystemData objectAtIndex: i];
448 [fname getCharacters: pBuffer];
449 size_t l = [fname length];
450 pBuffer += l + 1;
453 oOOData <<= oOOFileList;
455 else
457 oOOData = mData;
460 return oOOData;
463 DataFlavorMapper::DataFlavorMapper()
465 Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
466 mrXMimeCntFactory = MimeContentTypeFactory::create( xContext );
469 DataFlavorMapper::~DataFlavorMapper()
471 // release potential NSStrings
472 for( OfficeOnlyTypes::iterator it = maOfficeOnlyTypes.begin(); it != maOfficeOnlyTypes.end(); ++it )
474 [it->second release];
475 it->second = nil;
479 DataFlavor DataFlavorMapper::systemToOpenOfficeFlavor( const NSString* systemDataFlavor) const
481 DataFlavor oOOFlavor;
483 for (size_t i = 0; i < SIZE_FLAVOR_MAP; i++)
485 if ([systemDataFlavor caseInsensitiveCompare:const_cast<NSString*>(flavorMap[i].SystemFlavor)] == NSOrderedSame)
487 oOOFlavor.MimeType = OUString::createFromAscii(flavorMap[i].OOoFlavor);
488 oOOFlavor.HumanPresentableName = OUString::createFromAscii(flavorMap[i].HumanPresentableName);
489 oOOFlavor.DataType = flavorMap[i].DataTypeOUString ? cppu::UnoType<OUString>::get() : cppu::UnoType<Sequence<sal_Int8>>::get();
490 return oOOFlavor;
492 } // for
494 // look if this might be an internal type; if it comes in here it must have
495 // been through openOfficeToSystemFlavor before, so it should then be in the map
496 OUString aTryFlavor( NSStringToOUString( systemDataFlavor ) );
497 if( maOfficeOnlyTypes.find( aTryFlavor ) != maOfficeOnlyTypes.end() )
499 oOOFlavor.MimeType = aTryFlavor;
500 oOOFlavor.HumanPresentableName.clear();
501 oOOFlavor.DataType = cppu::UnoType<Sequence<sal_Int8>>::get();
504 return oOOFlavor;
507 const NSString* DataFlavorMapper::openOfficeToSystemFlavor( const DataFlavor& oOOFlavor, bool& rbInternal) const
509 const NSString* sysFlavor = nullptr;
510 rbInternal = false;
512 for( size_t i = 0; i < SIZE_FLAVOR_MAP; ++i )
514 if (oOOFlavor.MimeType.startsWith(OUString::createFromAscii(flavorMap[i].OOoFlavor)))
516 sysFlavor = flavorMap[i].SystemFlavor;
520 if(!sysFlavor)
522 rbInternal = true;
523 OfficeOnlyTypes::const_iterator it = maOfficeOnlyTypes.find( oOOFlavor.MimeType );
525 if( it == maOfficeOnlyTypes.end() )
526 sysFlavor = maOfficeOnlyTypes[ oOOFlavor.MimeType ] = OUStringToNSString( oOOFlavor.MimeType );
527 else
528 sysFlavor = it->second;
531 return sysFlavor;
534 NSString* DataFlavorMapper::openOfficeImageToSystemFlavor(NSPasteboard* pPasteboard)
536 NSArray *supportedTypes = [NSArray arrayWithObjects: NSTIFFPboardType, nil];
537 NSString *sysFlavor = [pPasteboard availableTypeFromArray:supportedTypes];
538 return sysFlavor;
541 DataProviderPtr_t DataFlavorMapper::getDataProvider( const NSString* systemFlavor, Reference<XTransferable> const & rTransferable) const
543 DataProviderPtr_t dp;
547 DataFlavor oOOFlavor = systemToOpenOfficeFlavor(systemFlavor);
549 Any data = rTransferable->getTransferData(oOOFlavor);
551 if (isByteSequenceType(data.getValueType()))
554 the HTMLFormatDataProvider prepends segment information to HTML
555 this is useful for exchange with MS Word (which brings this stuff from Windows)
556 but annoying for other applications. Since this extension is not a standard datatype
557 on the Mac, let us not provide but provide normal HTML
559 if ([systemFlavor caseInsensitiveCompare: NSHTMLPboardType] == NSOrderedSame)
561 dp = DataProviderPtr_t(new HTMLFormatDataProvider(data));
563 else
565 if ([systemFlavor caseInsensitiveCompare: NSTIFFPboardType] == NSOrderedSame)
567 dp = DataProviderPtr_t( new PNGDataProvider( data, NSTIFFFileType));
569 else if ([systemFlavor caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame)
571 dp = DataProviderPtr_t(new FileListDataProvider(data));
573 else
575 dp = DataProviderPtr_t(new ByteSequenceDataProvider(data));
578 else // Must be OUString type
580 SAL_WARN_IF(
581 !isOUStringType(data.getValueType()), "vcl",
582 "must be OUString type");
583 dp = DataProviderPtr_t(new UniDataProvider(data));
586 catch(UnsupportedFlavorException&)
588 // Somebody violates the contract of the clipboard
589 // interface @see XTransferable
592 return dp;
595 DataProviderPtr_t DataFlavorMapper::getDataProvider( const NSString* /*systemFlavor*/, NSArray* systemData)
597 return DataProviderPtr_t(new FileListDataProvider(systemData));
600 DataProviderPtr_t DataFlavorMapper::getDataProvider( const NSString* systemFlavor, NSData* systemData)
602 DataProviderPtr_t dp;
604 if ([systemFlavor caseInsensitiveCompare: NSStringPboardType] == NSOrderedSame)
606 dp = DataProviderPtr_t(new UniDataProvider(systemData));
608 else if ([systemFlavor caseInsensitiveCompare: NSHTMLPboardType] == NSOrderedSame)
610 dp = DataProviderPtr_t(new HTMLFormatDataProvider(systemData));
612 else if ([systemFlavor caseInsensitiveCompare: NSTIFFPboardType] == NSOrderedSame)
614 dp = DataProviderPtr_t( new PNGDataProvider(systemData, NSTIFFFileType));
616 else if ([systemFlavor caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame)
618 //dp = DataProviderPtr_t(new FileListDataProvider(systemData));
620 else
622 dp = DataProviderPtr_t(new ByteSequenceDataProvider(systemData));
625 return dp;
628 bool DataFlavorMapper::isValidMimeContentType(const OUString& contentType) const
630 bool result = true;
634 Reference<XMimeContentType> xCntType(mrXMimeCntFactory->createMimeContentType(contentType));
636 catch( IllegalArgumentException& )
638 result = false;
641 return result;
644 NSArray* DataFlavorMapper::flavorSequenceToTypesArray(const css::uno::Sequence<css::datatransfer::DataFlavor>& flavors) const
646 sal_uInt32 nFlavors = flavors.getLength();
647 NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity: 1];
649 bool bNeedDummyInternalFlavor(false);
651 for (sal_uInt32 i = 0; i < nFlavors; i++)
653 if( flavors[i].MimeType.startsWith("image/bmp") )
655 [array addObject: NSTIFFPboardType];
657 else
659 const NSString* str = openOfficeToSystemFlavor(flavors[i], bNeedDummyInternalFlavor);
661 if (str != nullptr)
663 [str retain];
664 [array addObject: str];
669 // #i89462# #i90747#
670 // in case no system flavor was found to report
671 // report at least one so D&D between OOo targets works
672 if( [array count] == 0 || bNeedDummyInternalFlavor)
674 [array addObject: PBTYPE_DUMMY_INTERNAL];
677 return [array autorelease];
680 css::uno::Sequence<css::datatransfer::DataFlavor> DataFlavorMapper::typesArrayToFlavorSequence(NSArray* types) const
682 int nFormats = [types count];
683 Sequence<DataFlavor> flavors;
685 for (int i = 0; i < nFormats; i++)
687 NSString* sysFormat = [types objectAtIndex: i];
688 DataFlavor oOOFlavor = systemToOpenOfficeFlavor(sysFormat);
690 if (isValidFlavor(oOOFlavor))
692 flavors.realloc(flavors.getLength() + 1);
693 flavors[flavors.getLength() - 1] = oOOFlavor;
697 return flavors;
700 NSArray* DataFlavorMapper::getAllSupportedPboardTypes()
702 NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity: SIZE_FLAVOR_MAP];
704 for (sal_uInt32 i = 0; i < SIZE_FLAVOR_MAP; i++)
706 [array addObject: flavorMap[i].SystemFlavor];
709 return [array autorelease];
712 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */