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