1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22 
23 #include "DataFlavorMapping.hxx"
24 #include "HtmlFmtFlt.hxx"
25 #include "PictToBmpFlt.hxx"
26 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
27 #include <com/sun/star/datatransfer/XMimeContentType.hpp>
28 #include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
29 #include <com/sun/star/lang/IllegalArgumentException.hpp>
30 #include <com/sun/star/uno/Sequence.hxx>
31 #include <comphelper/processfactory.hxx>
32 
33 #include <rtl/ustring.hxx>
34 #include <osl/endian.h>
35 
36 #include <cassert>
37 #include <string.h>
38 #include <string_view>
39 
40 #include <premac.h>
41 #include <Cocoa/Cocoa.h>
42 #include <postmac.h>
43 
44 using namespace ::com::sun::star::datatransfer;
45 using namespace ::com::sun::star::uno;
46 using namespace com::sun::star::lang;
47 using namespace cppu;
48 using namespace std;
49 
50 namespace
51 {
52   /* Determine whether or not a DataFlavor is valid.
53    */
isValidFlavor(const DataFlavor & aFlavor)54   bool isValidFlavor(const DataFlavor& aFlavor)
55   {
56     size_t len = aFlavor.MimeType.getLength();
57     Type dtype = aFlavor.DataType;
58     return ((len > 0) && ((dtype == cppu::UnoType<Sequence<sal_Int8>>::get()) || (dtype == cppu::UnoType<OUString>::get())));
59   }
60 
NSStringToOUString(const NSString * cfString)61   OUString NSStringToOUString( const NSString* cfString)
62   {
63     assert(cfString && "Invalid parameter");
64 
65     const char* utf8Str = [cfString UTF8String];
66     unsigned int len = rtl_str_getLength(utf8Str);
67 
68     return OUString(utf8Str, len, RTL_TEXTENCODING_UTF8);
69   }
70 
OUStringToNSString(std::u16string_view ustring)71   NSString* OUStringToNSString(std::u16string_view ustring)
72   {
73     OString utf8Str = OUStringToOString(ustring, RTL_TEXTENCODING_UTF8);
74     return [NSString stringWithCString: utf8Str.getStr() encoding: NSUTF8StringEncoding];
75   }
76 
77   const char* FLAVOR_SESX = "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
78   const char* FLAVOR_SLSDX = "application/x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link Source Descriptor (XML)\"";
79   const char* FLAVOR_ESX = "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
80   const char* FLAVOR_LSX = "application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\"";
81   const char* FLAVOR_EOX = "application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star Embedded Object (XML)\"";
82   const char* FLAVOR_SVXB = "application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\"";
83   const char* FLAVOR_GDIMF = "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
84   const char* FLAVOR_WMF = "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
85   const char* FLAVOR_EMF = "application/x-openoffice-emf;windows_formatname=\"Image EMF\"";
86   const char* FLAVOR_SODX = "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"";
87   const char* FLAVOR_LINK = "application/x-openoffice-link;windows_formatname=\"Link\"";
88   const char* FLAVOR_DUMMY_INTERNAL = "application/x-openoffice-internal";
89 
90   struct FlavorMap
91   {
92     const NSString* SystemFlavor;
93     const char* OOoFlavor;
94     const char* HumanPresentableName;
95     bool DataTypeOUString; // sequence<byte> otherwise
96   };
97 
98   // This is a list of the bidirectional mapping between (internal) MIME types and (system)
99   // pasteboard types.
100 
101   // Only pasteboard types mentioned here will be recognized, mapped, and available for pasting in a
102   // fresh LibreOffice process. When copy-pasting in-process, the situation is different.
103 
104   // Also MIME types not mentioned here will be stored on the pasteboard (using the same type name),
105   // though. But that is IMHO a bit pointless as they in general won't then be pasteable anyway in a
106   // new LibreOffice process. See the use of the maOfficeOnlyTypes array.
107 
108   // The SystemFlavor member is nil for the cases where there is no predefined pasteboard type UTI
109   // and we use the internal MIME type (media type) also on the pasteboard. That is OK in macOS,
110   // there is no requirement that the types are well-formed UTIs. It is different on iOS, I think,
111   // though. For an introduction to UTIs, see for instance
112   // https://alastairs-place.net/blog/2012/06/06/utis-are-better-than-you-think-and-heres-why/
113   //
114   // In those cases the MIME type might actually have parameters appended, separated by semicolons.
115   // At least the FLAVOR_SODX one must have at least a typename="%PRODUCTNAME %PRODUCTVERSION
116   // Spreadsheet" parameter (with macros expanded and translated) for LO to recognise it. See
117   // lcl_TestFormat() in sc/source/ui/view/cellsh.cxx.
118 
119   const FlavorMap flavorMap[] =
120     {
121       { NSPasteboardTypeString, "text/plain;charset=utf-16", "Unicode Text (UTF-16)", true },
122       { NSPasteboardTypeRTF, "text/rtf", "Rich Text Format", false },
123       { NSPasteboardTypePDF, "application/pdf", "PDF File", false },
124       { NSPasteboardTypeTIFF, "image/png", "Portable Network Graphics", false },
125       { NSPasteboardTypeHTML, "text/html", "Plain Html", false },
126 SAL_WNODEPRECATED_DECLARATIONS_PUSH
127           // "'NSFilenamesPboardType' is deprecated: first deprecated in macOS 10.14 - Create
128           // multiple pasteboard items with NSPasteboardTypeFileURL or kUTTypeFileURL instead"
129       { NSFilenamesPboardType, "application/x-openoffice-filelist;windows_formatname=\"FileList\"", "FileList", false },
130 SAL_WNODEPRECATED_DECLARATIONS_POP
131       { nil, FLAVOR_SESX, "Star Embed Source (XML)", false },
132       { nil, FLAVOR_SLSDX, "Star Link Source Descriptor (XML)", false },
133       { nil, FLAVOR_ESX, "Star Embed Source (XML)", false },
134       { nil, FLAVOR_LSX, "Star Link Source (XML)", false },
135       { nil, FLAVOR_EOX, "Star Embedded Object (XML)", false },
136       { nil, FLAVOR_SVXB, "SVXB (StarView Bitmap/Animation", false },
137       { nil, FLAVOR_GDIMF, "GDIMetaFile", false },
138       { nil, FLAVOR_WMF, "Windows MetaFile", false },
139       { nil, FLAVOR_EMF, "Windows Enhanced MetaFile", false },
140       { nil, FLAVOR_SODX, "Star Object Descriptor (XML)", false },
141       { nil, FLAVOR_LINK, "Dynamic Data Exchange (DDE link)", false },
142       { nil, FLAVOR_DUMMY_INTERNAL, "internal data",false }
143     };
144 
145   #define SIZE_FLAVOR_MAP (sizeof(flavorMap)/sizeof(FlavorMap))
146 
isByteSequenceType(const Type & theType)147   bool isByteSequenceType(const Type& theType)
148   {
149     return (theType == cppu::UnoType<Sequence<sal_Int8>>::get());
150   }
151 
isOUStringType(const Type & theType)152   bool isOUStringType(const Type& theType)
153   {
154     return (theType == cppu::UnoType<OUString>::get() );
155   }
156 
157 /* A base class for other data provider.
158  */
159 class DataProviderBaseImpl : public DataProvider
160 {
161 public:
162   DataProviderBaseImpl(const Any& data);
163   DataProviderBaseImpl(id data);
164   virtual ~DataProviderBaseImpl() override;
165 
166 protected:
167   Any mData;
168   //NSData* mSystemData;
169   id mSystemData;
170 };
171 
172 } // unnamed namespace
173 
DataProviderBaseImpl(const Any & data)174 DataProviderBaseImpl::DataProviderBaseImpl(const Any& data) :
175   mData(data),
176   mSystemData(nil)
177 {
178 }
179 
DataProviderBaseImpl(id data)180 DataProviderBaseImpl::DataProviderBaseImpl(id data) :
181   mSystemData(data)
182 {
183   [mSystemData retain];
184 }
185 
~DataProviderBaseImpl()186 DataProviderBaseImpl::~DataProviderBaseImpl()
187 {
188   if (mSystemData)
189     {
190       [mSystemData release];
191     }
192 }
193 
194 namespace {
195 
196 class UniDataProvider : public DataProviderBaseImpl
197 {
198 public:
199   UniDataProvider(const Any& data);
200 
201   UniDataProvider(NSData* data);
202 
203   virtual NSData* getSystemData() override;
204 
205   virtual Any getOOoData() override;
206 };
207 
208 }
209 
UniDataProvider(const Any & data)210 UniDataProvider::UniDataProvider(const Any& data) :
211   DataProviderBaseImpl(data)
212 {
213 }
214 
UniDataProvider(NSData * data)215 UniDataProvider::UniDataProvider(NSData* data) :
216   DataProviderBaseImpl(data)
217 {
218 }
219 
getSystemData()220 NSData* UniDataProvider::getSystemData()
221 {
222   OUString ustr;
223   mData >>= ustr;
224 
225   OString strUtf8;
226   ustr.convertToString(&strUtf8, RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS);
227 
228   return [NSData dataWithBytes: strUtf8.getStr() length: strUtf8.getLength()];
229 }
230 
getOOoData()231 Any UniDataProvider::getOOoData()
232 {
233   Any oOOData;
234 
235   if (mSystemData)
236     {
237       oOOData <<= OUString(static_cast<const char*>([mSystemData bytes]),
238                                  [mSystemData length],
239                                  RTL_TEXTENCODING_UTF8);
240     }
241   else
242     {
243       oOOData = mData;
244     }
245 
246   return oOOData;
247 }
248 
249 namespace {
250 
251 class ByteSequenceDataProvider : public DataProviderBaseImpl
252 {
253 public:
254   ByteSequenceDataProvider(const Any& data);
255 
256   ByteSequenceDataProvider(NSData* data);
257 
258   virtual NSData* getSystemData() override;
259 
260   virtual Any getOOoData() override;
261 };
262 
263 }
264 
ByteSequenceDataProvider(const Any & data)265 ByteSequenceDataProvider::ByteSequenceDataProvider(const Any& data) :
266   DataProviderBaseImpl(data)
267 {
268 }
269 
ByteSequenceDataProvider(NSData * data)270 ByteSequenceDataProvider::ByteSequenceDataProvider(NSData* data) :
271   DataProviderBaseImpl(data)
272 {
273 }
274 
getSystemData()275 NSData* ByteSequenceDataProvider::getSystemData()
276 {
277    Sequence<sal_Int8> rawData;
278    mData >>= rawData;
279 
280    return [NSData dataWithBytes: rawData.getArray() length: rawData.getLength()];
281 }
282 
getOOoData()283 Any ByteSequenceDataProvider::getOOoData()
284 {
285   Any oOOData;
286 
287   if (mSystemData)
288     {
289       unsigned int flavorDataLength = [mSystemData length];
290       Sequence<sal_Int8> byteSequence;
291       byteSequence.realloc(flavorDataLength);
292       memcpy(byteSequence.getArray(), [mSystemData bytes], flavorDataLength);
293       oOOData <<= byteSequence;
294     }
295   else
296     {
297       oOOData =  mData;
298     }
299 
300   return oOOData;
301 }
302 
303 namespace {
304 
305 class HTMLFormatDataProvider : public DataProviderBaseImpl
306 {
307 public:
308   HTMLFormatDataProvider(NSData* data);
309 
310   virtual NSData* getSystemData() override;
311 
312   virtual Any getOOoData() override;
313 };
314 
315 }
316 
HTMLFormatDataProvider(NSData * data)317 HTMLFormatDataProvider::HTMLFormatDataProvider(NSData* data) :
318   DataProviderBaseImpl(data)
319 {
320 }
321 
getSystemData()322 NSData* HTMLFormatDataProvider::getSystemData()
323 {
324   Sequence<sal_Int8> textHtmlData;
325   mData >>= textHtmlData;
326 
327   Sequence<sal_Int8> htmlFormatData = TextHtmlToHTMLFormat(textHtmlData);
328 
329   return [NSData dataWithBytes: htmlFormatData.getArray() length: htmlFormatData.getLength()];
330 }
331 
getOOoData()332 Any HTMLFormatDataProvider::getOOoData()
333 {
334   Any oOOData;
335 
336   if (mSystemData)
337     {
338       unsigned int flavorDataLength = [mSystemData length];
339       Sequence<sal_Int8> unkHtmlData;
340 
341       unkHtmlData.realloc(flavorDataLength);
342       memcpy(unkHtmlData.getArray(), [mSystemData bytes], flavorDataLength);
343 
344       Sequence<sal_Int8>* pPlainHtml = &unkHtmlData;
345       Sequence<sal_Int8> plainHtml;
346 
347       if (isHTMLFormat(unkHtmlData))
348         {
349           plainHtml = HTMLFormatToTextHtml(unkHtmlData);
350           pPlainHtml = &plainHtml;
351         }
352 
353       oOOData <<= *pPlainHtml;
354     }
355   else
356     {
357       oOOData = mData;
358     }
359 
360   return oOOData;
361 }
362 
363 namespace {
364 
365 
366 class PNGDataProvider : public DataProviderBaseImpl
367 {
368     NSBitmapImageFileType meImageType;
369 public:
370     PNGDataProvider( const Any&, NSBitmapImageFileType);
371 
372     PNGDataProvider( NSData*, NSBitmapImageFileType);
373 
374     virtual NSData* getSystemData() override;
375 
376     virtual Any getOOoData() override;
377 };
378 
379 }
380 
PNGDataProvider(const Any & data,NSBitmapImageFileType eImageType)381 PNGDataProvider::PNGDataProvider( const Any& data, NSBitmapImageFileType eImageType) :
382   DataProviderBaseImpl(data),
383   meImageType( eImageType )
384 {
385 }
386 
PNGDataProvider(NSData * data,NSBitmapImageFileType eImageType)387 PNGDataProvider::PNGDataProvider( NSData* data, NSBitmapImageFileType eImageType) :
388   DataProviderBaseImpl(data),
389   meImageType( eImageType )
390 {
391 }
392 
getSystemData()393 NSData* PNGDataProvider::getSystemData()
394 {
395     Sequence<sal_Int8> pngData;
396     mData >>= pngData;
397 
398     Sequence<sal_Int8> imgData;
399     NSData* sysData = nullptr;
400     if( PNGToImage( pngData, imgData, meImageType))
401         sysData = [NSData dataWithBytes: imgData.getArray() length: imgData.getLength()];
402 
403     return sysData;
404 }
405 
406 /* The AOO 'PCT' filter is not yet good enough to be used
407    and there is no flavor defined for exchanging 'PCT' with AOO
408    so we convert 'PCT' to a PNG and provide this to AOO
409 */
getOOoData()410 Any PNGDataProvider::getOOoData()
411 {
412     Any oOOData;
413 
414     if( mSystemData)
415     {
416         const unsigned int flavorDataLength = [mSystemData length];
417         Sequence<sal_Int8> imgData( flavorDataLength);
418         memcpy( imgData.getArray(), [mSystemData bytes], flavorDataLength);
419 
420         Sequence<sal_Int8> pngData;
421         if( ImageToPNG( imgData, pngData))
422             oOOData <<= pngData;
423     }
424     else
425     {
426         oOOData = mData;
427     }
428 
429     return oOOData;
430 }
431 
432 namespace {
433 
434 class FileListDataProvider : public DataProviderBaseImpl
435 {
436 public:
437   FileListDataProvider(const Any& data);
438   FileListDataProvider(NSArray* data);
439 
440   virtual NSData* getSystemData() override;
441   virtual Any getOOoData() override;
442 };
443 
444 }
445 
FileListDataProvider(const Any & data)446 FileListDataProvider::FileListDataProvider(const Any& data) :
447   DataProviderBaseImpl(data)
448 {
449 }
450 
FileListDataProvider(NSArray * data)451 FileListDataProvider::FileListDataProvider(NSArray* data) :
452   DataProviderBaseImpl(data)
453 {
454 }
455 
getSystemData()456 NSData* FileListDataProvider::getSystemData()
457 {
458   return [NSData data];
459 }
460 
getOOoData()461 Any FileListDataProvider::getOOoData()
462 {
463   Any oOOData;
464 
465   if (mSystemData)
466     {
467       size_t length = [mSystemData count];
468       size_t lenSeqRequired = 0;
469 
470       for (size_t i = 0; i < length; i++)
471         {
472           NSString* fname = [mSystemData objectAtIndex: i];
473           lenSeqRequired += [fname maximumLengthOfBytesUsingEncoding: NSUnicodeStringEncoding] + sizeof(unichar);
474         }
475 
476       Sequence<sal_Int8> oOOFileList(lenSeqRequired);
477       unichar* pBuffer = reinterpret_cast<unichar*>(oOOFileList.getArray());
478       memset(pBuffer, 0, lenSeqRequired);
479 
480       for (size_t i = 0; i < length; i++)
481         {
482           NSString* fname = [mSystemData objectAtIndex: i];
483           [fname getCharacters: pBuffer];
484           size_t l = [fname length];
485           pBuffer += l + 1;
486         }
487 
488       oOOData <<= oOOFileList;
489     }
490   else
491     {
492       oOOData = mData;
493     }
494 
495   return oOOData;
496 }
497 
DataFlavorMapper()498 DataFlavorMapper::DataFlavorMapper()
499 {
500     Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
501     mrXMimeCntFactory = MimeContentTypeFactory::create( xContext );
502 }
503 
~DataFlavorMapper()504 DataFlavorMapper::~DataFlavorMapper()
505 {
506     // release potential NSStrings
507     for( OfficeOnlyTypes::iterator it = maOfficeOnlyTypes.begin(); it != maOfficeOnlyTypes.end(); ++it )
508     {
509         [it->second release];
510         it->second = nil;
511     }
512 }
513 
systemToOpenOfficeFlavor(const NSString * systemDataFlavor) const514 DataFlavor DataFlavorMapper::systemToOpenOfficeFlavor( const NSString* systemDataFlavor) const
515 {
516     DataFlavor oOOFlavor;
517 
518     for (size_t i = 0; i < SIZE_FLAVOR_MAP; i++)
519     {
520         if ((flavorMap[i].SystemFlavor == nil && ([systemDataFlavor isEqualToString:[NSString stringWithUTF8String:flavorMap[i].OOoFlavor]]
521                                                   ||
522                                                   [systemDataFlavor hasPrefix:[[NSString stringWithUTF8String:flavorMap[i].OOoFlavor] stringByAppendingString:@";"]]))
523             ||
524             (flavorMap[i].SystemFlavor != nil && [systemDataFlavor isEqualToString:const_cast<NSString*>(flavorMap[i].SystemFlavor)]))
525         {
526           if (flavorMap[i].SystemFlavor == nil)
527               oOOFlavor.MimeType = NSStringToOUString(systemDataFlavor);
528           else
529               oOOFlavor.MimeType = OUString::createFromAscii(flavorMap[i].OOoFlavor);
530           oOOFlavor.HumanPresentableName = OUString::createFromAscii(flavorMap[i].HumanPresentableName);
531           oOOFlavor.DataType = flavorMap[i].DataTypeOUString ? cppu::UnoType<OUString>::get() : cppu::UnoType<Sequence<sal_Int8>>::get();
532           return oOOFlavor;
533         }
534     } // for
535 
536     // look if this might be an internal type; if it comes in here it must have
537     // been through openOfficeToSystemFlavor before, so it should then be in the map
538     OUString aTryFlavor( NSStringToOUString( systemDataFlavor ) );
539     if( maOfficeOnlyTypes.find( aTryFlavor ) != maOfficeOnlyTypes.end() )
540     {
541         oOOFlavor.MimeType = aTryFlavor;
542         oOOFlavor.HumanPresentableName.clear();
543         oOOFlavor.DataType = cppu::UnoType<Sequence<sal_Int8>>::get();
544     }
545 
546     return oOOFlavor;
547 }
548 
openOfficeToSystemFlavor(const DataFlavor & oOOFlavor,bool & rbInternal) const549 const NSString* DataFlavorMapper::openOfficeToSystemFlavor( const DataFlavor& oOOFlavor, bool& rbInternal) const
550 {
551     const NSString* sysFlavor = nullptr;
552     rbInternal = false;
553 
554     for( size_t i = 0; i < SIZE_FLAVOR_MAP; ++i )
555     {
556        if (oOOFlavor.MimeType.startsWith(OUString::createFromAscii(flavorMap[i].OOoFlavor)))
557         {
558             if (flavorMap[i].SystemFlavor != nil)
559                 sysFlavor = flavorMap[i].SystemFlavor;
560             else
561                 sysFlavor = OUStringToNSString(oOOFlavor.MimeType);
562         }
563     }
564 
565     if(!sysFlavor)
566     {
567         rbInternal = true;
568         OfficeOnlyTypes::const_iterator it = maOfficeOnlyTypes.find( oOOFlavor.MimeType );
569 
570         if( it == maOfficeOnlyTypes.end() )
571             sysFlavor = maOfficeOnlyTypes[ oOOFlavor.MimeType ] = OUStringToNSString( oOOFlavor.MimeType );
572         else
573             sysFlavor = it->second;
574     }
575 
576     return sysFlavor;
577 }
578 
openOfficeImageToSystemFlavor(NSPasteboard * pPasteboard)579 NSString* DataFlavorMapper::openOfficeImageToSystemFlavor(NSPasteboard* pPasteboard)
580 {
581     NSArray *supportedTypes = [NSArray arrayWithObjects: NSPasteboardTypeTIFF, nil];
582     NSString *sysFlavor = [pPasteboard availableTypeFromArray:supportedTypes];
583     return sysFlavor;
584 }
585 
getDataProvider(const NSString * systemFlavor,Reference<XTransferable> const & rTransferable) const586 DataProviderPtr_t DataFlavorMapper::getDataProvider( const NSString* systemFlavor, Reference<XTransferable> const & rTransferable) const
587 {
588   DataProviderPtr_t dp;
589 
590   try
591     {
592       DataFlavor oOOFlavor = systemToOpenOfficeFlavor(systemFlavor);
593 
594       Any data = rTransferable->getTransferData(oOOFlavor);
595 
596       if (isByteSequenceType(data.getValueType()))
597         {
598           /*
599              the HTMLFormatDataProvider prepends segment information to HTML
600              this is useful for exchange with MS Word (which brings this stuff from Windows)
601              but annoying for other applications. Since this extension is not a standard datatype
602              on the Mac, let us not provide but provide normal HTML
603 
604           if ([systemFlavor caseInsensitiveCompare: NSHTMLPboardType] == NSOrderedSame)
605             {
606               dp = DataProviderPtr_t(new HTMLFormatDataProvider(data));
607             }
608           else
609           */
610           if ([systemFlavor caseInsensitiveCompare: NSPasteboardTypeTIFF] == NSOrderedSame)
611             {
612               dp = DataProviderPtr_t( new PNGDataProvider( data, NSBitmapImageFileTypeTIFF));
613             }
614 SAL_WNODEPRECATED_DECLARATIONS_PUSH
615               // "'NSFilenamesPboardType' is deprecated: first deprecated in macOS 10.14 - Create
616               // multiple pasteboard items with NSPasteboardTypeFileURL or kUTTypeFileURL instead"
617           else if ([systemFlavor caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame)
618 SAL_WNODEPRECATED_DECLARATIONS_POP
619             {
620               dp = DataProviderPtr_t(new FileListDataProvider(data));
621             }
622           else
623             {
624               dp = DataProviderPtr_t(new ByteSequenceDataProvider(data));
625             }
626         }
627       else // Must be OUString type
628         {
629           SAL_WARN_IF(
630               !isOUStringType(data.getValueType()), "vcl",
631               "must be OUString type");
632           dp = DataProviderPtr_t(new UniDataProvider(data));
633         }
634     }
635   catch( const UnsupportedFlavorException& e )
636     {
637      SAL_WARN( "vcl.osx.clipboard", "DataFlavorMapper::getDataProvider(): Exception: " << e.Message );
638       // Somebody violates the contract of the clipboard
639       // interface @see XTransferable
640     }
641 
642   return dp;
643 }
644 
getDataProvider(const NSString *,NSArray * systemData)645 DataProviderPtr_t DataFlavorMapper::getDataProvider( const NSString* /*systemFlavor*/, NSArray* systemData)
646 {
647   return DataProviderPtr_t(new FileListDataProvider(systemData));
648 }
649 
getDataProvider(const NSString * systemFlavor,NSData * systemData)650 DataProviderPtr_t DataFlavorMapper::getDataProvider( const NSString* systemFlavor, NSData* systemData)
651 {
652   DataProviderPtr_t dp;
653 
654   if ([systemFlavor caseInsensitiveCompare: NSPasteboardTypeString] == NSOrderedSame)
655     {
656       dp = DataProviderPtr_t(new UniDataProvider(systemData));
657     }
658   else if ([systemFlavor caseInsensitiveCompare: NSPasteboardTypeHTML] == NSOrderedSame)
659     {
660       dp = DataProviderPtr_t(new HTMLFormatDataProvider(systemData));
661     }
662   else if ([systemFlavor caseInsensitiveCompare: NSPasteboardTypeTIFF] == NSOrderedSame)
663     {
664       dp = DataProviderPtr_t( new PNGDataProvider(systemData, NSBitmapImageFileTypeTIFF));
665     }
666 SAL_WNODEPRECATED_DECLARATIONS_PUSH
667       // "'NSFilenamesPboardType' is deprecated: first deprecated in macOS 10.14 - Create multiple
668       // pasteboard items with NSPasteboardTypeFileURL or kUTTypeFileURL instead"
669   else if ([systemFlavor caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame)
670 SAL_WNODEPRECATED_DECLARATIONS_POP
671     {
672       //dp = DataProviderPtr_t(new FileListDataProvider(systemData));
673     }
674   else
675     {
676       dp = DataProviderPtr_t(new ByteSequenceDataProvider(systemData));
677     }
678 
679   return dp;
680 }
681 
isValidMimeContentType(const OUString & contentType) const682 bool DataFlavorMapper::isValidMimeContentType(const OUString& contentType) const
683 {
684   bool result = true;
685 
686   try
687     {
688       Reference<XMimeContentType> xCntType(mrXMimeCntFactory->createMimeContentType(contentType));
689     }
690   catch( const IllegalArgumentException& e )
691     {
692       SAL_WARN("vcl.osx.clipboard", "DataFlavorMapper::isValidMimeContentType(): Exception: " << e.Message);
693       result = false;
694     }
695 
696   return result;
697 }
698 
flavorSequenceToTypesArray(const css::uno::Sequence<css::datatransfer::DataFlavor> & flavors) const699 NSArray* DataFlavorMapper::flavorSequenceToTypesArray(const css::uno::Sequence<css::datatransfer::DataFlavor>& flavors) const
700 {
701   sal_uInt32 nFlavors = flavors.getLength();
702   NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity: 1];
703 
704   bool bNeedDummyInternalFlavor(false);
705 
706   for (sal_uInt32 i = 0; i < nFlavors; i++)
707   {
708       if( flavors[i].MimeType.startsWith("image/bmp") )
709       {
710           [array addObject: NSPasteboardTypeTIFF];
711       }
712       else
713       {
714           const NSString* str = openOfficeToSystemFlavor(flavors[i], bNeedDummyInternalFlavor);
715 
716           if (str != nullptr)
717           {
718               [str retain];
719               [array addObject: str];
720           }
721       }
722   }
723 
724    // #i89462# #i90747#
725    // in case no system flavor was found to report
726    // report at least one so D&D between OOo targets works
727   if( [array count] == 0 || bNeedDummyInternalFlavor)
728   {
729       [array addObject: [NSString stringWithUTF8String: FLAVOR_DUMMY_INTERNAL]];
730   }
731 
732   return [array autorelease];
733 }
734 
typesArrayToFlavorSequence(NSArray * types) const735 css::uno::Sequence<css::datatransfer::DataFlavor> DataFlavorMapper::typesArrayToFlavorSequence(NSArray* types) const
736 {
737   int nFormats = [types count];
738   Sequence<DataFlavor> flavors;
739 
740   for (int i = 0; i < nFormats; i++)
741     {
742       NSString* sysFormat = [types objectAtIndex: i];
743       DataFlavor oOOFlavor = systemToOpenOfficeFlavor(sysFormat);
744 
745       if (isValidFlavor(oOOFlavor))
746         {
747           flavors.realloc(flavors.getLength() + 1);
748           flavors[flavors.getLength() - 1] = oOOFlavor;
749         }
750     }
751 
752   return flavors;
753 }
754 
getAllSupportedPboardTypes()755 NSArray* DataFlavorMapper::getAllSupportedPboardTypes()
756 {
757   NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity: SIZE_FLAVOR_MAP];
758 
759   for (sal_uInt32 i = 0; i < SIZE_FLAVOR_MAP; i++)
760     {
761       if (flavorMap[i].SystemFlavor != nil)
762           [array addObject: flavorMap[i].SystemFlavor];
763       else
764           [array addObject: [NSString stringWithUTF8String: flavorMap[i].OOoFlavor]];
765     }
766 
767   return [array autorelease];
768 }
769 
770 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
771