1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 #include <sal/types.h>
27 
28 #ifndef _TRANSFERABLE_HXX_
29 #include "OSXTransferable.hxx"
30 #endif
31 
32 #include "DataFlavorMapping.hxx"
33 
34 using namespace rtl;
35 using namespace std;
36 using namespace osl;
37 using namespace cppu;
38 using namespace com::sun::star::uno;
39 using namespace com::sun::star::datatransfer;
40 using namespace com::sun::star::io;
41 using namespace com::sun::star::lang;
42 using namespace com::sun::star::container;
43 
44 const Type CPPUTYPE_SEQINT8  = getCppuType((Sequence<sal_Int8>*)0);
45 const Type CPPUTYPE_OUSTRING = getCppuType((OUString*)0);
46 
47 namespace // private
48 {
49 	bool isValidFlavor( const DataFlavor& aFlavor )
50 	{
51 	  size_t len = aFlavor.MimeType.getLength();
52 	  Type dtype = aFlavor.DataType;
53 	  return ((len > 0) && ((dtype == CPPUTYPE_SEQINT8) || (dtype == CPPUTYPE_OUSTRING)));
54 	}
55 
56 } // namespace private
57 
58 
59 OSXTransferable::OSXTransferable(const Reference<XMimeContentTypeFactory> rXMimeCntFactory,
60 								 DataFlavorMapperPtr_t pDataFlavorMapper,
61 								 NSPasteboard* pasteboard) :
62   mrXMimeCntFactory(rXMimeCntFactory),
63   mDataFlavorMapper(pDataFlavorMapper),
64   mPasteboard(pasteboard)
65 {
66   [mPasteboard retain];
67 
68   initClipboardItemList();
69 }
70 
71 
72 OSXTransferable::~OSXTransferable()
73 {
74   [mPasteboard release];
75 }
76 
77 
78 Any SAL_CALL OSXTransferable::getTransferData( const DataFlavor& aFlavor )
79   throw( UnsupportedFlavorException, IOException, RuntimeException )
80 {
81   if (!isValidFlavor(aFlavor) || !isDataFlavorSupported(aFlavor))
82 	{
83 	  throw UnsupportedFlavorException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Unsupported data flavor")),
84 									   static_cast<XTransferable*>(this));
85 	}
86 
87   bool bInternal(false);
88   NSString* sysFormat =
89       (aFlavor.MimeType.compareToAscii( "image/png", 9 ) == 0)
90       ? mDataFlavorMapper->openOfficeImageToSystemFlavor( mPasteboard )
91       : mDataFlavorMapper->openOfficeToSystemFlavor(aFlavor, bInternal);
92   DataProviderPtr_t dp;
93 
94   if ([sysFormat caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame)
95 	{
96 	  NSArray* sysData = [mPasteboard propertyListForType: sysFormat];
97 	  dp = mDataFlavorMapper->getDataProvider(sysFormat, sysData);
98 	}
99   else
100 	{
101 	  NSData* sysData = [mPasteboard dataForType: sysFormat];
102 	  dp = mDataFlavorMapper->getDataProvider(sysFormat, sysData);
103 	}
104 
105   if (dp.get() == NULL)
106 	{
107 	  throw UnsupportedFlavorException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Unsupported data flavor")),
108 									   static_cast<XTransferable*>(this));
109 	}
110 
111   return dp->getOOoData();
112 }
113 
114 
115 bool OSXTransferable::isUnicodeText(const DataFlavor& flavor)
116 {
117   return (flavor.DataType == CPPUTYPE_OUSTRING);
118 }
119 
120 
121 Sequence< DataFlavor > SAL_CALL OSXTransferable::getTransferDataFlavors(  )
122 	throw( RuntimeException )
123 {
124   return mFlavorList;
125 }
126 
127 
128 sal_Bool SAL_CALL OSXTransferable::isDataFlavorSupported(const DataFlavor& aFlavor)
129 	throw( RuntimeException )
130 {
131 	for (sal_Int32 i = 0; i < mFlavorList.getLength(); i++)
132 	  if (compareDataFlavors(aFlavor, mFlavorList[i]))
133 		return sal_True;
134 
135 	return sal_False;
136 }
137 
138 
139 void OSXTransferable::initClipboardItemList()
140 {
141   NSArray* pboardFormats = [mPasteboard types];
142 
143   if (pboardFormats == NULL)
144 	{
145 	  throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot get clipboard data")),
146 							 static_cast<XTransferable*>(this));
147 	}
148 
149   mFlavorList = mDataFlavorMapper->typesArrayToFlavorSequence(pboardFormats);
150 }
151 
152 
153 /* Compares two DataFlavors. Returns true if both DataFlavor have the same media type
154    and the number of parameter and all parameter values do match otherwise false
155    is returned.
156  */
157 bool OSXTransferable::compareDataFlavors(const DataFlavor& lhs, const DataFlavor& rhs )
158 {
159 	try
160 	{
161 		Reference<XMimeContentType> xLhs(mrXMimeCntFactory->createMimeContentType(lhs.MimeType));
162 		Reference<XMimeContentType> xRhs(mrXMimeCntFactory->createMimeContentType(rhs.MimeType));
163 
164 		if (!xLhs->getFullMediaType().equalsIgnoreAsciiCase(xRhs->getFullMediaType()) ||
165 			!cmpAllContentTypeParameter(xLhs, xRhs))
166 		  {
167 			return false;
168 		  }
169 	}
170 	catch( IllegalArgumentException& )
171 	{
172 		OSL_ENSURE( sal_False, "Invalid content type detected" );
173 		return false;
174 	}
175 
176 	return true;
177 }
178 
179 
180 bool OSXTransferable::cmpAllContentTypeParameter(const Reference<XMimeContentType> xLhs,
181 											   const Reference<XMimeContentType> xRhs) const
182 {
183   Sequence<OUString> xLhsFlavors = xLhs->getParameters();
184   Sequence<OUString> xRhsFlavors = xRhs->getParameters();
185 
186   // Stop here if the number of parameters is different already
187   if (xLhsFlavors.getLength() != xRhsFlavors.getLength())
188 	return false;
189 
190   try
191 	{
192 	  OUString pLhs;
193 	  OUString pRhs;
194 
195 	  for (sal_Int32 i = 0; i < xLhsFlavors.getLength(); i++)
196 		{
197 		  pLhs = xLhs->getParameterValue(xLhsFlavors[i]);
198 		  pRhs = xRhs->getParameterValue(xLhsFlavors[i]);
199 
200 		  if (!pLhs.equalsIgnoreAsciiCase(pRhs))
201 			{
202 			  return false;
203 			}
204 		}
205 	}
206   catch(IllegalArgumentException&)
207 	{
208 	  return false;
209 	}
210 
211   return true;
212 }
213