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 NSString* sysFormat = 88 (aFlavor.MimeType.compareToAscii( "image/png", 9 ) == 0) 89 ? mDataFlavorMapper->openOfficeImageToSystemFlavor( mPasteboard ) 90 : mDataFlavorMapper->openOfficeToSystemFlavor(aFlavor); 91 DataProviderPtr_t dp; 92 93 if ([sysFormat caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame) 94 { 95 NSArray* sysData = [mPasteboard propertyListForType: sysFormat]; 96 dp = mDataFlavorMapper->getDataProvider(sysFormat, sysData); 97 } 98 else 99 { 100 NSData* sysData = [mPasteboard dataForType: sysFormat]; 101 dp = mDataFlavorMapper->getDataProvider(sysFormat, sysData); 102 } 103 104 if (dp.get() == NULL) 105 { 106 throw UnsupportedFlavorException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Unsupported data flavor")), 107 static_cast<XTransferable*>(this)); 108 } 109 110 return dp->getOOoData(); 111 } 112 113 114 bool OSXTransferable::isUnicodeText(const DataFlavor& flavor) 115 { 116 return (flavor.DataType == CPPUTYPE_OUSTRING); 117 } 118 119 120 Sequence< DataFlavor > SAL_CALL OSXTransferable::getTransferDataFlavors( ) 121 throw( RuntimeException ) 122 { 123 return mFlavorList; 124 } 125 126 127 sal_Bool SAL_CALL OSXTransferable::isDataFlavorSupported(const DataFlavor& aFlavor) 128 throw( RuntimeException ) 129 { 130 for (sal_Int32 i = 0; i < mFlavorList.getLength(); i++) 131 if (compareDataFlavors(aFlavor, mFlavorList[i])) 132 return sal_True; 133 134 return sal_False; 135 } 136 137 138 void OSXTransferable::initClipboardItemList() 139 { 140 NSArray* pboardFormats = [mPasteboard types]; 141 142 if (pboardFormats == NULL) 143 { 144 throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot get clipboard data")), 145 static_cast<XTransferable*>(this)); 146 } 147 148 mFlavorList = mDataFlavorMapper->typesArrayToFlavorSequence(pboardFormats); 149 } 150 151 152 /* Compares two DataFlavors. Returns true if both DataFlavor have the same media type 153 and the number of parameter and all parameter values do match otherwise false 154 is returned. 155 */ 156 bool OSXTransferable::compareDataFlavors(const DataFlavor& lhs, const DataFlavor& rhs ) 157 { 158 try 159 { 160 Reference<XMimeContentType> xLhs(mrXMimeCntFactory->createMimeContentType(lhs.MimeType)); 161 Reference<XMimeContentType> xRhs(mrXMimeCntFactory->createMimeContentType(rhs.MimeType)); 162 163 if (!xLhs->getFullMediaType().equalsIgnoreAsciiCase(xRhs->getFullMediaType()) || 164 !cmpAllContentTypeParameter(xLhs, xRhs)) 165 { 166 return false; 167 } 168 } 169 catch( IllegalArgumentException& ) 170 { 171 OSL_ENSURE( sal_False, "Invalid content type detected" ); 172 return false; 173 } 174 175 return true; 176 } 177 178 179 bool OSXTransferable::cmpAllContentTypeParameter(const Reference<XMimeContentType> xLhs, 180 const Reference<XMimeContentType> xRhs) const 181 { 182 Sequence<OUString> xLhsFlavors = xLhs->getParameters(); 183 Sequence<OUString> xRhsFlavors = xRhs->getParameters(); 184 185 // Stop here if the number of parameters is different already 186 if (xLhsFlavors.getLength() != xRhsFlavors.getLength()) 187 return false; 188 189 try 190 { 191 OUString pLhs; 192 OUString pRhs; 193 194 for (sal_Int32 i = 0; i < xLhsFlavors.getLength(); i++) 195 { 196 pLhs = xLhs->getParameterValue(xLhsFlavors[i]); 197 pRhs = xRhs->getParameterValue(xLhsFlavors[i]); 198 199 if (!pLhs.equalsIgnoreAsciiCase(pRhs)) 200 { 201 return false; 202 } 203 } 204 } 205 catch(IllegalArgumentException&) 206 { 207 return false; 208 } 209 210 return true; 211 } 212