1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
22 #include <utility>
23
24 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
25 #include <com/sun/star/lang/IllegalArgumentException.hpp>
26 #include <sal/types.h>
27 #include <osl/diagnose.h>
28
29 #include "OSXTransferable.hxx"
30
31 #include "DataFlavorMapping.hxx"
32
33 using namespace std;
34 using namespace osl;
35 using namespace cppu;
36 using namespace com::sun::star::uno;
37 using namespace com::sun::star::datatransfer;
38 using namespace com::sun::star::lang;
39
40 namespace
41 {
isValidFlavor(const DataFlavor & aFlavor)42 bool isValidFlavor( const DataFlavor& aFlavor )
43 {
44 size_t len = aFlavor.MimeType.getLength();
45 Type dtype = aFlavor.DataType;
46 return ((len > 0) && ((dtype == cppu::UnoType<Sequence<sal_Int8>>::get()) || (dtype == cppu::UnoType<OUString>::get())));
47 }
48
cmpAllContentTypeParameter(const Reference<XMimeContentType> & xLhs,const Reference<XMimeContentType> & xRhs)49 bool cmpAllContentTypeParameter(const Reference<XMimeContentType> & xLhs,
50 const Reference<XMimeContentType> & xRhs)
51 {
52 Sequence<OUString> xLhsFlavors = xLhs->getParameters();
53 Sequence<OUString> xRhsFlavors = xRhs->getParameters();
54
55 // Stop here if the number of parameters is different already
56 if (xLhsFlavors.getLength() != xRhsFlavors.getLength())
57 return false;
58
59 try
60 {
61 OUString pLhs;
62 OUString pRhs;
63
64 for (sal_Int32 i = 0; i < xLhsFlavors.getLength(); i++)
65 {
66 pLhs = xLhs->getParameterValue(xLhsFlavors[i]);
67 pRhs = xRhs->getParameterValue(xLhsFlavors[i]);
68
69 if (!pLhs.equalsIgnoreAsciiCase(pRhs))
70 {
71 return false;
72 }
73 }
74 }
75 catch(IllegalArgumentException&)
76 {
77 return false;
78 }
79
80 return true;
81 }
82
83 } // unnamed namespace
84
OSXTransferable(const Reference<XMimeContentTypeFactory> & rXMimeCntFactory,DataFlavorMapperPtr_t pDataFlavorMapper,NSPasteboard * pasteboard)85 OSXTransferable::OSXTransferable(const Reference<XMimeContentTypeFactory> & rXMimeCntFactory,
86 DataFlavorMapperPtr_t pDataFlavorMapper,
87 NSPasteboard* pasteboard) :
88 mrXMimeCntFactory(rXMimeCntFactory),
89 mDataFlavorMapper(pDataFlavorMapper),
90 mPasteboard(pasteboard)
91 {
92 [mPasteboard retain];
93
94 initClipboardItemList();
95 }
96
~OSXTransferable()97 OSXTransferable::~OSXTransferable()
98 {
99 [mPasteboard release];
100 }
101
getTransferData(const DataFlavor & aFlavor)102 Any SAL_CALL OSXTransferable::getTransferData( const DataFlavor& aFlavor )
103 {
104 if (!isValidFlavor(aFlavor) || !isDataFlavorSupported(aFlavor))
105 {
106 throw UnsupportedFlavorException("AquaClipboard: Unsupported data flavor",
107 static_cast<XTransferable*>(this));
108 }
109
110 bool bInternal(false);
111 NSString const * sysFormat =
112 (aFlavor.MimeType.startsWith("image/png"))
113 ? DataFlavorMapper::openOfficeImageToSystemFlavor( mPasteboard )
114 : mDataFlavorMapper->openOfficeToSystemFlavor(aFlavor, bInternal);
115 DataProviderPtr_t dp;
116
117 SAL_WNODEPRECATED_DECLARATIONS_PUSH
118 // "'NSFilenamesPboardType' is deprecated: first deprecated in macOS 10.14 - Create multiple
119 // pasteboard items with NSPasteboardTypeFileURL or kUTTypeFileURL instead"
120 if ([sysFormat caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame)
121 SAL_WNODEPRECATED_DECLARATIONS_POP
122 {
123 NSArray* sysData = [mPasteboard propertyListForType: const_cast<NSString *>(sysFormat)];
124 dp = DataFlavorMapper::getDataProvider(sysFormat, sysData);
125 }
126 else
127 {
128 NSData* sysData = [mPasteboard dataForType: const_cast<NSString *>(sysFormat)];
129 dp = DataFlavorMapper::getDataProvider(sysFormat, sysData);
130 }
131
132 if (!dp)
133 {
134 throw UnsupportedFlavorException("AquaClipboard: Unsupported data flavor",
135 static_cast<XTransferable*>(this));
136 }
137
138 return dp->getOOoData();
139 }
140
getTransferDataFlavors()141 Sequence< DataFlavor > SAL_CALL OSXTransferable::getTransferDataFlavors( )
142 {
143 return mFlavorList;
144 }
145
isDataFlavorSupported(const DataFlavor & aFlavor)146 sal_Bool SAL_CALL OSXTransferable::isDataFlavorSupported(const DataFlavor& aFlavor)
147 {
148 for (const DataFlavor& rFlavor : std::as_const(mFlavorList))
149 if (compareDataFlavors(aFlavor, rFlavor))
150 return true;
151
152 return false;
153 }
154
initClipboardItemList()155 void OSXTransferable::initClipboardItemList()
156 {
157 NSArray* pboardFormats = [mPasteboard types];
158
159 if (pboardFormats == nullptr)
160 {
161 throw RuntimeException("AquaClipboard: Cannot get clipboard data",
162 static_cast<XTransferable*>(this));
163 }
164
165 mFlavorList = mDataFlavorMapper->typesArrayToFlavorSequence(pboardFormats);
166 }
167
168 /* Compares two DataFlavors. Returns true if both DataFlavor have the same media type
169 and the number of parameter and all parameter values do match otherwise false
170 is returned.
171 */
compareDataFlavors(const DataFlavor & lhs,const DataFlavor & rhs)172 bool OSXTransferable::compareDataFlavors(const DataFlavor& lhs, const DataFlavor& rhs )
173 {
174 try
175 {
176 Reference<XMimeContentType> xLhs(mrXMimeCntFactory->createMimeContentType(lhs.MimeType));
177 Reference<XMimeContentType> xRhs(mrXMimeCntFactory->createMimeContentType(rhs.MimeType));
178
179 if (!xLhs->getFullMediaType().equalsIgnoreAsciiCase(xRhs->getFullMediaType()) ||
180 !cmpAllContentTypeParameter(xLhs, xRhs))
181 {
182 return false;
183 }
184 }
185 catch( IllegalArgumentException& )
186 {
187 OSL_FAIL( "Invalid content type detected" );
188 return false;
189 }
190
191 return true;
192 }
193
194 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
195