1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
39 #include <Cocoa/Cocoa.h>
42 using namespace ::com::sun::star::datatransfer
;
43 using namespace ::com::sun::star::uno
;
44 using namespace com::sun::star::lang
;
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";
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
150 DataProviderBaseImpl(const Any
& data
);
151 DataProviderBaseImpl(id data
);
152 virtual ~DataProviderBaseImpl() override
;
156 //NSData* mSystemData;
160 DataProviderBaseImpl::DataProviderBaseImpl(const Any
& data
) :
166 DataProviderBaseImpl::DataProviderBaseImpl(id data
) :
169 [mSystemData retain
];
172 DataProviderBaseImpl::~DataProviderBaseImpl()
176 [mSystemData release
];
180 class UniDataProvider
: public DataProviderBaseImpl
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()
208 ustr
.convertToString(&strUtf8
, RTL_TEXTENCODING_UTF8
, OUSTRING_TO_OSTRING_CVTFLAGS
);
210 return [NSData dataWithBytes
: strUtf8
.getStr() length
: strUtf8
.getLength()];
213 Any
UniDataProvider::getOOoData()
219 oOOData
<<= OUString(static_cast<const sal_Char
*>([mSystemData bytes
]),
220 [mSystemData length
],
221 RTL_TEXTENCODING_UTF8
);
231 class ByteSequenceDataProvider
: public DataProviderBaseImpl
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
;
258 return [NSData dataWithBytes
: rawData
.getArray() length
: rawData
.getLength()];
261 Any
ByteSequenceDataProvider::getOOoData()
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
;
281 class HTMLFormatDataProvider
: public DataProviderBaseImpl
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()
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
;
337 class PNGDataProvider
: public DataProviderBaseImpl
339 NSBitmapImageFileType meImageType
;
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
;
367 Sequence
<sal_Int8
> imgData
;
368 NSData
* sysData
= nullptr;
369 if( PNGToImage( pngData
, imgData
, meImageType
))
370 sysData
= [NSData dataWithBytes
: imgData
.getArray() length
: imgData
.getLength()];
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()
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
))
401 class FileListDataProvider
: public DataProviderBaseImpl
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()
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
];
453 oOOData
<<= oOOFileList
;
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
];
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();
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();
507 const NSString
* DataFlavorMapper::openOfficeToSystemFlavor( const DataFlavor
& oOOFlavor
, bool& rbInternal
) const
509 const NSString
* sysFlavor
= nullptr;
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
;
523 OfficeOnlyTypes::const_iterator it
= maOfficeOnlyTypes
.find( oOOFlavor
.MimeType
);
525 if( it
== maOfficeOnlyTypes
.end() )
526 sysFlavor
= maOfficeOnlyTypes
[ oOOFlavor
.MimeType
] = OUStringToNSString( oOOFlavor
.MimeType
);
528 sysFlavor
= it
->second
;
534 NSString
* DataFlavorMapper::openOfficeImageToSystemFlavor(NSPasteboard
* pPasteboard
)
536 NSArray
*supportedTypes
= [NSArray arrayWithObjects
: NSTIFFPboardType
, nil
];
537 NSString
*sysFlavor
= [pPasteboard availableTypeFromArray
:supportedTypes
];
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));
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
));
575 dp
= DataProviderPtr_t(new ByteSequenceDataProvider(data
));
578 else // Must be OUString type
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
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));
622 dp
= DataProviderPtr_t(new ByteSequenceDataProvider(systemData
));
628 bool DataFlavorMapper::isValidMimeContentType(const OUString
& contentType
) const
634 Reference
<XMimeContentType
> xCntType(mrXMimeCntFactory
->createMimeContentType(contentType
));
636 catch( IllegalArgumentException
& )
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
];
659 const NSString
* str
= openOfficeToSystemFlavor(flavors
[i
], bNeedDummyInternalFlavor
);
664 [array addObject
: str
];
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
;
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: */