1 /* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
25 #include <com/sun/star/datatransfer/XMimeContentType.hpp>
26 #include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
27 #include <com/sun/star/lang/IllegalArgumentException.hpp>
28 #include <com/sun/star/uno/Sequence.hxx>
29 #include <comphelper/processfactory.hxx>
31 #include <rtl/ustring.hxx>
32 #include <sal/log.hxx>
33 #include <osl/endian.h>
39 #include <UIKit/UIKit.h>
40 #include <MobileCoreServices/MobileCoreServices.h>
43 using namespace css::datatransfer
;
44 using namespace css::uno
;
45 using namespace css::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
;
57 && ((dtype
== cppu::UnoType
<Sequence
<sal_Int8
>>::get())
58 || (dtype
== cppu::UnoType
<OUString
>::get())));
61 OUString
NSStringToOUString(const NSString
* cfString
)
63 assert(cfString
&& "Invalid parameter");
65 const char* utf8Str
= [cfString UTF8String
];
66 unsigned int len
= rtl_str_getLength(utf8Str
);
68 return OUString(utf8Str
, len
, RTL_TEXTENCODING_UTF8
);
71 NSString
* OUStringToNSString(const OUString
& ustring
)
73 OString utf8Str
= OUStringToOString(ustring
, RTL_TEXTENCODING_UTF8
);
74 return [NSString stringWithCString
:utf8Str
.getStr() encoding
:NSUTF8StringEncoding
];
77 NSString
* PBTYPE_PLAINTEXT
= (__bridge NSString
*)kUTTypePlainText
;
78 // Nope. See commented-out use below.
79 // NSString* PBTYPE_UTF8PLAINTEXT = (__bridge NSString*)kUTTypeUTF8PlainText;
80 NSString
* PBTYPE_RTF
= (__bridge NSString
*)kUTTypeRTF
;
81 NSString
* PBTYPE_PNG
= (__bridge NSString
*)kUTTypePNG
;
82 NSString
* PBTYPE_JPEG
= (__bridge NSString
*)kUTTypeJPEG
;
83 NSString
* PBTYPE_HTML
= (__bridge NSString
*)kUTTypeHTML
;
84 NSString
* PBTYPE_PDF
= (__bridge NSString
*)kUTTypePDF
;
86 = @
"application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
87 NSString
* PBTYPE_SLSDX
= @
"application/"
88 @
"x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link "
89 @
"Source Descriptor (XML)\"";
91 = @
"application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\"";
92 NSString
* PBTYPE_EOX
= @
"application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star "
93 @
"Embedded Object (XML)\"";
95 = @
"application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\"";
96 NSString
* PBTYPE_GDIMF
= @
"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
97 NSString
* PBTYPE_SODX
= @
"application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star "
98 @
"Object Descriptor (XML)\"";
99 NSString
* PBTYPE_DUMMY_INTERNAL
= @
"application/x-openoffice-internal";
101 const char* FLAVOR_SESX
102 = "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
103 const char* FLAVOR_SLSDX
= "application/"
104 "x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link "
105 "Source Descriptor (XML)\"";
106 const char* FLAVOR_LSX
107 = "application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\"";
108 const char* FLAVOR_EOX
109 = "application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star Embedded Object (XML)\"";
110 const char* FLAVOR_SVXB
111 = "application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\"";
112 const char* FLAVOR_GDIMF
113 = "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
114 const char* FLAVOR_SODX
= "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star "
115 "Object Descriptor (XML)\"";
116 const char* FLAVOR_DUMMY_INTERNAL
= "application/x-openoffice-internal";
120 NSString
* SystemFlavor
;
121 const char* OOoFlavor
;
122 const char* HumanPresentableName
;
123 bool DataTypeOUString
; // sequence<byte> otherwise
126 static const FlavorMap flavorMap
[]
127 = { { PBTYPE_PLAINTEXT
, "text/plain;charset=utf-16", "Unicode Text (UTF-16)", true },
128 // Nope. The LO code does not understand text/plain in UTF-8. Which is a shame.
129 // PBTYPE_UTF8PLAINTEXT, "text/plain;charset=utf-8", "Unicode Text (UTF-8)", false },
130 { PBTYPE_RTF
, "text/rtf", "Rich Text Format", false },
131 { PBTYPE_PNG
, "image/png", "Portable Network Graphics", false },
132 { PBTYPE_JPEG
, "image/jpeg", "JPEG", false },
133 { PBTYPE_HTML
, "text/html", "Plain HTML", false },
134 { PBTYPE_PDF
, "application/pdf", "PDF File", false },
135 { PBTYPE_SESX
, FLAVOR_SESX
, "Star Embed Source (XML)", false },
136 { PBTYPE_SLSDX
, FLAVOR_SLSDX
, "Star Link Source Descriptor (XML)", false },
137 { PBTYPE_LSX
, FLAVOR_LSX
, "Star Link Source (XML)", false },
138 { PBTYPE_EOX
, FLAVOR_EOX
, "Star Embedded Object (XML)", false },
139 { PBTYPE_SVXB
, FLAVOR_SVXB
, "SVXB (StarView Bitmap/Animation", false },
140 { PBTYPE_GDIMF
, FLAVOR_GDIMF
, "GDIMetaFile", false },
141 { PBTYPE_SODX
, FLAVOR_SODX
, "Star Object Descriptor (XML)", false },
142 { PBTYPE_DUMMY_INTERNAL
, FLAVOR_DUMMY_INTERNAL
, "internal data", false } };
144 #define SIZE_FLAVOR_MAP (sizeof(flavorMap) / sizeof(FlavorMap))
146 inline bool isByteSequenceType(const Type
& theType
)
148 return (theType
== cppu::UnoType
<Sequence
<sal_Int8
>>::get());
151 inline bool isOUStringType(const Type
& theType
)
153 return (theType
== cppu::UnoType
<OUString
>::get());
156 } // unnamed namespace
158 /* A base class for other data provider.
160 class DataProviderBaseImpl
: public DataProvider
163 DataProviderBaseImpl(const Any
& data
);
164 DataProviderBaseImpl(id data
);
165 virtual ~DataProviderBaseImpl() override
;
169 //NSData* mSystemData;
173 DataProviderBaseImpl::DataProviderBaseImpl(const Any
& data
)
179 DataProviderBaseImpl::DataProviderBaseImpl(id data
)
182 [mSystemData retain
];
185 DataProviderBaseImpl::~DataProviderBaseImpl()
189 [mSystemData release
];
193 class UniDataProvider
: public DataProviderBaseImpl
196 UniDataProvider(const Any
& data
);
197 UniDataProvider(NSData
* data
);
199 NSData
* getSystemData() override
;
200 Any
getOOoData() override
;
203 UniDataProvider::UniDataProvider(const Any
& data
)
204 : DataProviderBaseImpl(data
)
208 UniDataProvider::UniDataProvider(NSData
* data
)
209 : DataProviderBaseImpl(data
)
213 NSData
* UniDataProvider::getSystemData()
219 ustr
.convertToString(&strUtf8
, RTL_TEXTENCODING_UTF8
, OUSTRING_TO_OSTRING_CVTFLAGS
);
221 return [NSData dataWithBytes
:strUtf8
.getStr() length
:strUtf8
.getLength()];
224 Any
UniDataProvider::getOOoData()
230 oOOData
<<= OUString(static_cast<const sal_Char
*>([mSystemData bytes
]),
231 [mSystemData length
], RTL_TEXTENCODING_UTF8
);
241 class ByteSequenceDataProvider
: public DataProviderBaseImpl
244 ByteSequenceDataProvider(const Any
& data
);
245 ByteSequenceDataProvider(NSData
* data
);
247 NSData
* getSystemData() override
;
248 Any
getOOoData() override
;
251 ByteSequenceDataProvider::ByteSequenceDataProvider(const Any
& data
)
252 : DataProviderBaseImpl(data
)
256 ByteSequenceDataProvider::ByteSequenceDataProvider(NSData
* data
)
257 : DataProviderBaseImpl(data
)
261 NSData
* ByteSequenceDataProvider::getSystemData()
263 Sequence
<sal_Int8
> rawData
;
266 return [NSData dataWithBytes
:rawData
.getArray() length
:rawData
.getLength()];
269 Any
ByteSequenceDataProvider::getOOoData()
275 unsigned int flavorDataLength
= [mSystemData length
];
276 Sequence
<sal_Int8
> byteSequence
;
277 byteSequence
.realloc(flavorDataLength
);
278 memcpy(byteSequence
.getArray(), [mSystemData bytes
], flavorDataLength
);
279 oOOData
<<= byteSequence
;
289 class HTMLFormatDataProvider
: public DataProviderBaseImpl
292 HTMLFormatDataProvider(NSData
* data
);
294 NSData
* getSystemData() override
;
295 Any
getOOoData() override
;
298 HTMLFormatDataProvider::HTMLFormatDataProvider(NSData
* data
)
299 : DataProviderBaseImpl(data
)
303 NSData
* HTMLFormatDataProvider::getSystemData()
305 Sequence
<sal_Int8
> textHtmlData
;
306 mData
>>= textHtmlData
;
308 Sequence
<sal_Int8
> htmlFormatData
= TextHtmlToHTMLFormat(textHtmlData
);
310 return [NSData dataWithBytes
:htmlFormatData
.getArray() length
:htmlFormatData
.getLength()];
313 Any
HTMLFormatDataProvider::getOOoData()
319 unsigned int flavorDataLength
= [mSystemData length
];
320 Sequence
<sal_Int8
> unkHtmlData
;
322 unkHtmlData
.realloc(flavorDataLength
);
323 memcpy(unkHtmlData
.getArray(), [mSystemData bytes
], flavorDataLength
);
325 Sequence
<sal_Int8
>* pPlainHtml
= &unkHtmlData
;
326 Sequence
<sal_Int8
> plainHtml
;
328 if (isHTMLFormat(unkHtmlData
))
330 plainHtml
= HTMLFormatToTextHtml(unkHtmlData
);
331 pPlainHtml
= &plainHtml
;
334 oOOData
<<= *pPlainHtml
;
344 DataFlavorMapper::DataFlavorMapper()
346 Reference
<XComponentContext
> xContext
= comphelper::getProcessComponentContext();
347 mrXMimeCntFactory
= MimeContentTypeFactory::create(xContext
);
350 DataFlavorMapper::~DataFlavorMapper()
352 // release potential NSStrings
353 for (OfficeOnlyTypes::iterator it
= maOfficeOnlyTypes
.begin(); it
!= maOfficeOnlyTypes
.end();
356 [it
->second release
];
361 DataFlavor
DataFlavorMapper::systemToOpenOfficeFlavor(const NSString
* systemDataFlavor
) const
363 DataFlavor oOOFlavor
;
365 for (size_t i
= 0; i
< SIZE_FLAVOR_MAP
; i
++)
367 if ([systemDataFlavor
368 caseInsensitiveCompare
:const_cast<NSString
*>(flavorMap
[i
].SystemFlavor
)]
371 oOOFlavor
.MimeType
= OUString::createFromAscii(flavorMap
[i
].OOoFlavor
);
372 oOOFlavor
.HumanPresentableName
373 = OUString::createFromAscii(flavorMap
[i
].HumanPresentableName
);
374 oOOFlavor
.DataType
= flavorMap
[i
].DataTypeOUString
375 ? cppu::UnoType
<OUString
>::get()
376 : cppu::UnoType
<Sequence
<sal_Int8
>>::get();
381 // look if this might be an internal type; if it comes in here it must have
382 // been through openOfficeToSystemFlavor before, so it should then be in the map
383 OUString
aTryFlavor(NSStringToOUString(systemDataFlavor
));
384 if (maOfficeOnlyTypes
.find(aTryFlavor
) != maOfficeOnlyTypes
.end())
386 oOOFlavor
.MimeType
= aTryFlavor
;
387 oOOFlavor
.HumanPresentableName
.clear();
388 oOOFlavor
.DataType
= cppu::UnoType
<Sequence
<sal_Int8
>>::get();
394 NSString
* DataFlavorMapper::openOfficeToSystemFlavor(const DataFlavor
& oOOFlavor
,
395 bool& rbInternal
) const
397 NSString
* sysFlavor
= nullptr;
400 for (size_t i
= 0; i
< SIZE_FLAVOR_MAP
; ++i
)
402 if (oOOFlavor
.MimeType
.startsWith(OUString::createFromAscii(flavorMap
[i
].OOoFlavor
)))
404 sysFlavor
= flavorMap
[i
].SystemFlavor
;
410 // For some reason, if we allow text/html, we get an OSL_ENSURE failure in xmloff that
411 // apparently is a symptom of something being seriously wrong:
412 // xmloff/source/transform/OOo2Oasis.cxx:1925: duplicate doc handler
413 // Because is then followed a bit later by an assertion failure:
414 // Assertion failed: (!m_pFirst && !m_pLast && "There are still indices registered"), function ~SwIndexReg, file [...]/sw/source/core/bastyp/index.cxx, line 226
416 if (oOOFlavor
.MimeType
== "text/html")
420 OfficeOnlyTypes::const_iterator it
= maOfficeOnlyTypes
.find(oOOFlavor
.MimeType
);
422 if (it
== maOfficeOnlyTypes
.end())
423 sysFlavor
= maOfficeOnlyTypes
[oOOFlavor
.MimeType
]
424 = OUStringToNSString(oOOFlavor
.MimeType
);
426 sysFlavor
= it
->second
;
432 NSString
* DataFlavorMapper::openOfficeImageToSystemFlavor(UIPasteboard
* pPasteboard
)
434 if ([pPasteboard containsPasteboardTypes
:@
[ PBTYPE_PNG
]])
436 else if ([pPasteboard containsPasteboardTypes
:@
[ PBTYPE_JPEG
]])
438 else if ([pPasteboard containsPasteboardTypes
:@
[ PBTYPE_PDF
]])
444 DataFlavorMapper::getDataProvider(const NSString
* systemFlavor
,
445 Reference
<XTransferable
> const& rTransferable
) const
447 DataProviderPtr_t dp
;
451 DataFlavor oOOFlavor
= systemToOpenOfficeFlavor(systemFlavor
);
453 Any data
= rTransferable
->getTransferData(oOOFlavor
);
455 if (isByteSequenceType(data
.getValueType()))
457 dp
= DataProviderPtr_t(new ByteSequenceDataProvider(data
));
459 else // Must be OUString type
461 SAL_WARN_IF(!isOUStringType(data
.getValueType()), "vcl", "must be OUString type");
462 dp
= DataProviderPtr_t(new UniDataProvider(data
));
465 catch (UnsupportedFlavorException
&)
467 // Somebody violates the contract of the clipboard
468 // interface @see XTransferable
474 DataProviderPtr_t
DataFlavorMapper::getDataProvider(const NSString
* systemFlavor
,
477 DataProviderPtr_t dp
;
479 if ([systemFlavor caseInsensitiveCompare
:PBTYPE_PLAINTEXT
] == NSOrderedSame
)
481 dp
= DataProviderPtr_t(new UniDataProvider(systemData
));
483 else if ([systemFlavor caseInsensitiveCompare
:PBTYPE_HTML
] == NSOrderedSame
)
485 dp
= DataProviderPtr_t(new HTMLFormatDataProvider(systemData
));
489 dp
= DataProviderPtr_t(new ByteSequenceDataProvider(systemData
));
495 bool DataFlavorMapper::isValidMimeContentType(const OUString
& contentType
) const
501 Reference
<XMimeContentType
> xCntType(mrXMimeCntFactory
->createMimeContentType(contentType
));
503 catch (IllegalArgumentException
&)
511 NSArray
* DataFlavorMapper::flavorSequenceToTypesArray(
512 const css::uno::Sequence
<css::datatransfer::DataFlavor
>& flavors
) const
514 const sal_uInt32 nFlavors
= flavors
.getLength();
515 NSMutableArray
* array
= [[NSMutableArray alloc
] initWithCapacity
:1];
517 bool bNeedDummyInternalFlavor(false);
519 for (sal_uInt32 i
= 0; i
< nFlavors
; i
++)
521 if (flavors
[i
].MimeType
.startsWith("image/bmp"))
523 [array addObject
:PBTYPE_PNG
];
527 const NSString
* str
= openOfficeToSystemFlavor(flavors
[i
], bNeedDummyInternalFlavor
);
532 [array addObject
:str
];
538 // in case no system flavor was found to report
539 // report at least one so D&D between OOo targets works
540 if ([array count
] == 0 || bNeedDummyInternalFlavor
)
542 [array addObject
:PBTYPE_DUMMY_INTERNAL
];
545 return [array autorelease
];
548 css::uno::Sequence
<css::datatransfer::DataFlavor
>
549 DataFlavorMapper::typesArrayToFlavorSequence(NSArray
* types
) const
551 int nFormats
= [types count
];
552 Sequence
<DataFlavor
> flavors
;
554 for (int i
= 0; i
< nFormats
; i
++)
556 NSString
* sysFormat
= [types objectAtIndex
:i
];
557 DataFlavor oOOFlavor
= systemToOpenOfficeFlavor(sysFormat
);
559 if (isValidFlavor(oOOFlavor
))
561 flavors
.realloc(flavors
.getLength() + 1);
562 flavors
[flavors
.getLength() - 1] = oOOFlavor
;
563 SAL_INFO("vcl.ios.clipboard",
564 "Mapped " << [sysFormat UTF8String
] << " to " << oOOFlavor
.MimeType
);
571 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */