calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / vcl / ios / DataFlavorMapping.cxx
blob14bf0f6f43d7a7ea6d8b967dcccbf37d04b3900b
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_UTF8PLAINTEXT = (__bridge NSString*)kUTTypeUTF8PlainText;
78 NSString* PBTYPE_RTF = (__bridge NSString*)kUTTypeRTF;
79 NSString* PBTYPE_PNG = (__bridge NSString*)kUTTypePNG;
80 NSString* PBTYPE_JPEG = (__bridge NSString*)kUTTypeJPEG;
81 NSString* PBTYPE_HTML = (__bridge NSString*)kUTTypeHTML;
82 NSString* PBTYPE_PDF = (__bridge NSString*)kUTTypePDF;
84 const char* FLAVOR_SESX
85 = "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
86 const char* FLAVOR_SLSDX = "application/"
87 "x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link "
88 "Source Descriptor (XML)\"";
89 const char* FLAVOR_LSX
90 = "application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\"";
91 const char* FLAVOR_EOX
92 = "application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star Embedded Object (XML)\"";
93 const char* FLAVOR_SVXB
94 = "application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\"";
95 const char* FLAVOR_GDIMF
96 = "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
97 const char* FLAVOR_SODX = "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star "
98 "Object Descriptor (XML)\"";
99 struct FlavorMap
101 NSString* SystemFlavor;
102 const char* OOoFlavor;
103 const char* HumanPresentableName;
104 bool DataTypeOUString; // sequence<byte> otherwise
107 // The SystemFlavor member is nil for the cases where there is no predefined pasteboard type UTI and
108 // we use the internal MIME type (media type) also on the pasteboard. That is OK, there dos not seem
109 // to be a requirement that the types are well-formed UTIs even on iOS. For an introduction to UTIs,
110 // see for instance
111 // https://alastairs-place.net/blog/2012/06/06/utis-are-better-than-you-think-and-heres-why/
113 // In those cases the MIME type might actually have parameters appended, separated by semicolons.
114 // At least the FLAVOR_SODX one must have at least a typename="%PRODUCTNAME %PRODUCTVERSION
115 // Spreadsheet" parameter (with macros expanded and translated) for LO to recognise it. See
116 // lcl_TestFormat() in sc/source/ui/view/cellsh.cxx.
118 static const FlavorMap flavorMap[]
119 = { { PBTYPE_UTF8PLAINTEXT, "text/plain;charset=utf-16", "Unicode Text (UTF-16)", true },
120 { PBTYPE_RTF, "text/rtf", "Rich Text Format", false },
121 { PBTYPE_PNG, "image/png", "Portable Network Graphics", false },
122 { PBTYPE_JPEG, "image/jpeg", "JPEG", false },
123 { PBTYPE_HTML, "text/html", "Plain HTML", false },
124 { PBTYPE_PDF, "application/pdf", "PDF File", false },
125 { nil, FLAVOR_SESX, "Star Embed Source (XML)", false },
126 { nil, FLAVOR_SLSDX, "Star Link Source Descriptor (XML)", false },
127 { nil, FLAVOR_LSX, "Star Link Source (XML)", false },
128 { nil, FLAVOR_EOX, "Star Embedded Object (XML)", false },
129 { nil, FLAVOR_SVXB, "SVXB (StarView Bitmap/Animation", false },
130 { nil, FLAVOR_GDIMF, "GDIMetaFile", false },
131 { nil, FLAVOR_SODX, "Star Object Descriptor (XML)", false } };
133 #define SIZE_FLAVOR_MAP (sizeof(flavorMap) / sizeof(FlavorMap))
135 inline bool isByteSequenceType(const Type& theType)
137 return (theType == cppu::UnoType<Sequence<sal_Int8>>::get());
140 inline bool isOUStringType(const Type& theType)
142 return (theType == cppu::UnoType<OUString>::get());
145 } // unnamed namespace
147 /* A base class for other data provider.
149 class DataProviderBaseImpl : public DataProvider
151 public:
152 DataProviderBaseImpl(const Any& data);
153 DataProviderBaseImpl(id data);
154 virtual ~DataProviderBaseImpl() override;
156 protected:
157 Any mData;
158 //NSData* mSystemData;
159 id mSystemData;
162 DataProviderBaseImpl::DataProviderBaseImpl(const Any& data)
163 : mData(data)
164 , mSystemData(nil)
168 DataProviderBaseImpl::DataProviderBaseImpl(id data)
169 : mSystemData(data)
171 [mSystemData retain];
174 DataProviderBaseImpl::~DataProviderBaseImpl()
176 if (mSystemData)
178 [mSystemData release];
182 class Utf8DataProvider : public DataProviderBaseImpl
184 public:
185 Utf8DataProvider(const Any& data);
186 Utf8DataProvider(NSData* data);
188 NSData* getSystemData() override;
189 Any getOOoData() override;
192 Utf8DataProvider::Utf8DataProvider(const Any& data)
193 : DataProviderBaseImpl(data)
197 Utf8DataProvider::Utf8DataProvider(NSData* data)
198 : DataProviderBaseImpl(data)
202 NSData* Utf8DataProvider::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 Utf8DataProvider::getOOoData()
215 Any oOOData;
217 if (mSystemData)
219 oOOData <<= OUString(static_cast<const char*>([mSystemData bytes]), [mSystemData length],
220 RTL_TEXTENCODING_UTF8);
222 else
224 oOOData = mData;
227 return oOOData;
230 class ByteSequenceDataProvider : public DataProviderBaseImpl
232 public:
233 ByteSequenceDataProvider(const Any& data);
234 ByteSequenceDataProvider(NSData* data);
236 NSData* getSystemData() override;
237 Any getOOoData() override;
240 ByteSequenceDataProvider::ByteSequenceDataProvider(const Any& data)
241 : DataProviderBaseImpl(data)
245 ByteSequenceDataProvider::ByteSequenceDataProvider(NSData* data)
246 : DataProviderBaseImpl(data)
250 NSData* ByteSequenceDataProvider::getSystemData()
252 Sequence<sal_Int8> rawData;
253 mData >>= rawData;
255 return [NSData dataWithBytes:rawData.getArray() length:rawData.getLength()];
258 Any ByteSequenceDataProvider::getOOoData()
260 Any oOOData;
262 if (mSystemData)
264 unsigned int flavorDataLength = [mSystemData length];
265 Sequence<sal_Int8> byteSequence;
266 byteSequence.realloc(flavorDataLength);
267 memcpy(byteSequence.getArray(), [mSystemData bytes], flavorDataLength);
268 oOOData <<= byteSequence;
270 else
272 oOOData = mData;
275 return oOOData;
278 class HTMLFormatDataProvider : public DataProviderBaseImpl
280 public:
281 HTMLFormatDataProvider(NSData* data);
283 NSData* getSystemData() override;
284 Any getOOoData() override;
287 HTMLFormatDataProvider::HTMLFormatDataProvider(NSData* data)
288 : DataProviderBaseImpl(data)
292 NSData* HTMLFormatDataProvider::getSystemData()
294 Sequence<sal_Int8> textHtmlData;
295 mData >>= textHtmlData;
297 Sequence<sal_Int8> htmlFormatData = TextHtmlToHTMLFormat(textHtmlData);
299 return [NSData dataWithBytes:htmlFormatData.getArray() length:htmlFormatData.getLength()];
302 Any HTMLFormatDataProvider::getOOoData()
304 Any oOOData;
306 if (mSystemData)
308 unsigned int flavorDataLength = [mSystemData length];
309 Sequence<sal_Int8> unkHtmlData;
311 unkHtmlData.realloc(flavorDataLength);
312 memcpy(unkHtmlData.getArray(), [mSystemData bytes], flavorDataLength);
314 Sequence<sal_Int8>* pPlainHtml = &unkHtmlData;
315 Sequence<sal_Int8> plainHtml;
317 if (isHTMLFormat(unkHtmlData))
319 plainHtml = HTMLFormatToTextHtml(unkHtmlData);
320 pPlainHtml = &plainHtml;
323 oOOData <<= *pPlainHtml;
325 else
327 oOOData = mData;
330 return oOOData;
333 DataFlavorMapper::DataFlavorMapper()
335 Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
336 mrXMimeCntFactory = MimeContentTypeFactory::create(xContext);
339 DataFlavorMapper::~DataFlavorMapper()
341 // release potential NSStrings
342 for (OfficeOnlyTypes::iterator it = maOfficeOnlyTypes.begin(); it != maOfficeOnlyTypes.end();
343 ++it)
345 [it->second release];
346 it->second = nil;
350 DataFlavor DataFlavorMapper::systemToOpenOfficeFlavor(const NSString* systemDataFlavor) const
352 DataFlavor oOOFlavor;
354 for (size_t i = 0; i < SIZE_FLAVOR_MAP; i++)
356 if ((flavorMap[i].SystemFlavor == nil
357 && ([systemDataFlavor
358 isEqualToString:[NSString stringWithUTF8String:flavorMap[i].OOoFlavor]]
360 [systemDataFlavor hasPrefix:[[NSString stringWithUTF8String:flavorMap[i].OOoFlavor]
361 stringByAppendingString:@";"]]))
362 || (flavorMap[i].SystemFlavor != nil &&
363 [systemDataFlavor
364 isEqualToString:const_cast<NSString*>(flavorMap[i].SystemFlavor)]))
366 if (flavorMap[i].SystemFlavor == nil)
367 oOOFlavor.MimeType = NSStringToOUString(systemDataFlavor);
368 else
369 oOOFlavor.MimeType = OUString::createFromAscii(flavorMap[i].OOoFlavor);
370 oOOFlavor.HumanPresentableName
371 = OUString::createFromAscii(flavorMap[i].HumanPresentableName);
372 oOOFlavor.DataType = flavorMap[i].DataTypeOUString
373 ? cppu::UnoType<OUString>::get()
374 : cppu::UnoType<Sequence<sal_Int8>>::get();
375 return oOOFlavor;
377 } // for
379 // look if this might be an internal type; if it comes in here it must have
380 // been through openOfficeToSystemFlavor before, so it should then be in the map
381 OUString aTryFlavor(NSStringToOUString(systemDataFlavor));
382 if (maOfficeOnlyTypes.find(aTryFlavor) != maOfficeOnlyTypes.end())
384 oOOFlavor.MimeType = aTryFlavor;
385 oOOFlavor.HumanPresentableName.clear();
386 oOOFlavor.DataType = cppu::UnoType<Sequence<sal_Int8>>::get();
389 return oOOFlavor;
392 NSString* DataFlavorMapper::openOfficeToSystemFlavor(const DataFlavor& oOOFlavor,
393 bool& rbInternal) const
395 NSString* sysFlavor = nullptr;
396 rbInternal = false;
398 for (size_t i = 0; i < SIZE_FLAVOR_MAP; ++i)
400 if (oOOFlavor.MimeType.startsWith(OUString::createFromAscii(flavorMap[i].OOoFlavor)))
402 if (flavorMap[i].SystemFlavor != nil)
403 sysFlavor = flavorMap[i].SystemFlavor;
404 else
405 sysFlavor = OUStringToNSString(oOOFlavor.MimeType);
409 if (!sysFlavor)
411 // For some reason, if we allow text/html, we get an OSL_ENSURE failure in xmloff that
412 // apparently is a symptom of something being seriously wrong:
413 // xmloff/source/transform/OOo2Oasis.cxx:1925: duplicate doc handler
414 // Because is then followed a bit later by an assertion failure:
415 // Assertion failed: (!m_pFirst && !m_pLast && "There are still indices registered"), function ~SwContentIndexReg, file [...]/sw/source/core/bastyp/index.cxx, line 226
417 if (oOOFlavor.MimeType == "text/html")
418 return nil;
420 rbInternal = true;
421 OfficeOnlyTypes::const_iterator it = maOfficeOnlyTypes.find(oOOFlavor.MimeType);
423 if (it == maOfficeOnlyTypes.end())
424 sysFlavor = maOfficeOnlyTypes[oOOFlavor.MimeType]
425 = OUStringToNSString(oOOFlavor.MimeType);
426 else
427 sysFlavor = it->second;
430 return sysFlavor;
433 NSString* DataFlavorMapper::openOfficeImageToSystemFlavor()
435 if ([[UIPasteboard generalPasteboard] containsPasteboardTypes:@[ PBTYPE_PNG ]])
436 return PBTYPE_PNG;
437 else if ([[UIPasteboard generalPasteboard] containsPasteboardTypes:@[ PBTYPE_JPEG ]])
438 return PBTYPE_JPEG;
439 else if ([[UIPasteboard generalPasteboard] containsPasteboardTypes:@[ PBTYPE_PDF ]])
440 return PBTYPE_PDF;
441 return @"";
444 DataProviderPtr_t
445 DataFlavorMapper::getDataProvider(const NSString* systemFlavor,
446 Reference<XTransferable> const& rTransferable) const
448 DataProviderPtr_t dp;
452 DataFlavor oOOFlavor = systemToOpenOfficeFlavor(systemFlavor);
454 Any data = rTransferable->getTransferData(oOOFlavor);
456 if (isByteSequenceType(data.getValueType()))
458 dp = DataProviderPtr_t(new ByteSequenceDataProvider(data));
460 else // Must be OUString type
462 SAL_WARN_IF(!isOUStringType(data.getValueType()), "vcl", "must be OUString type");
463 dp = DataProviderPtr_t(new Utf8DataProvider(data));
466 catch (const UnsupportedFlavorException& e)
468 SAL_WARN("vcl.ios.clipboard",
469 "DataFlavorMapper::getDataProvider(): Exception: " << e.Message);
470 // Somebody violates the contract of the clipboard
471 // interface @see XTransferable
474 return dp;
477 DataProviderPtr_t DataFlavorMapper::getDataProvider(const NSString* systemFlavor,
478 NSData* systemData)
480 DataProviderPtr_t dp;
482 if (systemData == nil)
483 return dp;
485 if ([systemFlavor caseInsensitiveCompare:PBTYPE_UTF8PLAINTEXT] == NSOrderedSame)
487 dp = DataProviderPtr_t(new Utf8DataProvider(systemData));
489 else if ([systemFlavor caseInsensitiveCompare:PBTYPE_HTML] == NSOrderedSame)
491 dp = DataProviderPtr_t(new HTMLFormatDataProvider(systemData));
493 else
495 dp = DataProviderPtr_t(new ByteSequenceDataProvider(systemData));
498 return dp;
501 bool DataFlavorMapper::isValidMimeContentType(const OUString& contentType) const
503 bool result = true;
507 Reference<XMimeContentType> xCntType(mrXMimeCntFactory->createMimeContentType(contentType));
509 catch (const IllegalArgumentException& e)
511 SAL_WARN("vcl.ios.clipboard",
512 "DataFlavorMapper::isValidMimeContentType(): Exception: " << e.Message);
513 result = false;
516 return result;
519 NSArray* DataFlavorMapper::flavorSequenceToTypesArray(
520 const css::uno::Sequence<css::datatransfer::DataFlavor>& flavors) const
522 const sal_uInt32 nFlavors = flavors.getLength();
523 NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity:1];
525 bool bNeedDummyInternalFlavor(false);
527 for (sal_uInt32 i = 0; i < nFlavors; i++)
529 if (flavors[i].MimeType.startsWith("image/bmp"))
531 [array addObject:PBTYPE_PNG];
533 else
535 const NSString* str = openOfficeToSystemFlavor(flavors[i], bNeedDummyInternalFlavor);
537 if (str != nil)
539 [str retain];
540 [array addObject:str];
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.getArray()[flavors.getLength() - 1] = oOOFlavor;
563 SAL_INFO("vcl.ios.clipboard",
564 "Mapped " << [sysFormat UTF8String] << " to " << oOOFlavor.MimeType);
566 else
568 SAL_INFO("vcl.ios.clipboard",
569 "Was not able to map " << [sysFormat UTF8String] << " to an internal flavour");
573 return flavors;
576 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */