bump product version to 6.4.0.3
[LibreOffice.git] / vcl / ios / DataFlavorMapping.cxx
blob2978e64afa4e5bfc5b03f4c459ee5034c0865ba0
1 /* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 <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>
35 #include <cassert>
36 #include <cstring>
38 #include <premac.h>
39 #include <UIKit/UIKit.h>
40 #include <MobileCoreServices/MobileCoreServices.h>
41 #include <postmac.h>
43 using namespace css::datatransfer;
44 using namespace css::uno;
45 using namespace css::lang;
46 using namespace cppu;
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)
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;
85 NSString* PBTYPE_SESX
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)\"";
90 NSString* PBTYPE_LSX
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)\"";
94 NSString* PBTYPE_SVXB
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";
118 struct FlavorMap
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
162 public:
163 DataProviderBaseImpl(const Any& data);
164 DataProviderBaseImpl(id data);
165 virtual ~DataProviderBaseImpl() override;
167 protected:
168 Any mData;
169 //NSData* mSystemData;
170 id mSystemData;
173 DataProviderBaseImpl::DataProviderBaseImpl(const Any& data)
174 : mData(data)
175 , mSystemData(nil)
179 DataProviderBaseImpl::DataProviderBaseImpl(id data)
180 : mSystemData(data)
182 [mSystemData retain];
185 DataProviderBaseImpl::~DataProviderBaseImpl()
187 if (mSystemData)
189 [mSystemData release];
193 class UniDataProvider : public DataProviderBaseImpl
195 public:
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()
215 OUString ustr;
216 mData >>= ustr;
218 OString strUtf8;
219 ustr.convertToString(&strUtf8, RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS);
221 return [NSData dataWithBytes:strUtf8.getStr() length:strUtf8.getLength()];
224 Any UniDataProvider::getOOoData()
226 Any oOOData;
228 if (mSystemData)
230 oOOData <<= OUString(static_cast<const sal_Char*>([mSystemData bytes]),
231 [mSystemData length], RTL_TEXTENCODING_UTF8);
233 else
235 oOOData = mData;
238 return oOOData;
241 class ByteSequenceDataProvider : public DataProviderBaseImpl
243 public:
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;
264 mData >>= rawData;
266 return [NSData dataWithBytes:rawData.getArray() length:rawData.getLength()];
269 Any ByteSequenceDataProvider::getOOoData()
271 Any oOOData;
273 if (mSystemData)
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;
281 else
283 oOOData = mData;
286 return oOOData;
289 class HTMLFormatDataProvider : public DataProviderBaseImpl
291 public:
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()
315 Any oOOData;
317 if (mSystemData)
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;
336 else
338 oOOData = mData;
341 return oOOData;
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();
354 ++it)
356 [it->second release];
357 it->second = nil;
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)]
369 == NSOrderedSame)
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();
377 return oOOFlavor;
379 } // for
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();
391 return oOOFlavor;
394 NSString* DataFlavorMapper::openOfficeToSystemFlavor(const DataFlavor& oOOFlavor,
395 bool& rbInternal) const
397 NSString* sysFlavor = nullptr;
398 rbInternal = false;
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;
408 if (!sysFlavor)
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")
417 return nil;
419 rbInternal = true;
420 OfficeOnlyTypes::const_iterator it = maOfficeOnlyTypes.find(oOOFlavor.MimeType);
422 if (it == maOfficeOnlyTypes.end())
423 sysFlavor = maOfficeOnlyTypes[oOOFlavor.MimeType]
424 = OUStringToNSString(oOOFlavor.MimeType);
425 else
426 sysFlavor = it->second;
429 return sysFlavor;
432 NSString* DataFlavorMapper::openOfficeImageToSystemFlavor(UIPasteboard* pPasteboard)
434 if ([pPasteboard containsPasteboardTypes:@[ PBTYPE_PNG ]])
435 return PBTYPE_PNG;
436 else if ([pPasteboard containsPasteboardTypes:@[ PBTYPE_JPEG ]])
437 return PBTYPE_JPEG;
438 else if ([pPasteboard containsPasteboardTypes:@[ PBTYPE_PDF ]])
439 return PBTYPE_PDF;
440 return @"";
443 DataProviderPtr_t
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
471 return dp;
474 DataProviderPtr_t DataFlavorMapper::getDataProvider(const NSString* systemFlavor,
475 NSData* systemData)
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));
487 else
489 dp = DataProviderPtr_t(new ByteSequenceDataProvider(systemData));
492 return dp;
495 bool DataFlavorMapper::isValidMimeContentType(const OUString& contentType) const
497 bool result = true;
501 Reference<XMimeContentType> xCntType(mrXMimeCntFactory->createMimeContentType(contentType));
503 catch (IllegalArgumentException&)
505 result = false;
508 return result;
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];
525 else
527 const NSString* str = openOfficeToSystemFlavor(flavors[i], bNeedDummyInternalFlavor);
529 if (str != nil)
531 [str retain];
532 [array addObject:str];
537 // #i89462# #i90747#
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);
568 return flavors;
571 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */