1 /* 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #import "CDataTransferer.h" 27 #include "sun_lwawt_macosx_CDataTransferer.h" 28 29 #import <AppKit/AppKit.h> 30 #import <JavaNativeFoundation/JavaNativeFoundation.h> 31 #import "jni_util.h" 32 33 #include "ThreadUtilities.h" 34 35 36 // ***** NOTE ***** This dictionary corresponds to the static array predefinedClipboardNames 37 // in CDataTransferer.java. 38 NSMutableDictionary *sStandardMappings = nil; 39 40 NSMutableDictionary *getMappingTable() { 41 if (sStandardMappings == nil) { 42 sStandardMappings = [[NSMutableDictionary alloc] init]; 43 [sStandardMappings setObject:NSStringPboardType 44 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_STRING]]; 45 [sStandardMappings setObject:NSFilenamesPboardType 46 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_FILE]]; 47 [sStandardMappings setObject:NSTIFFPboardType 48 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_TIFF]]; 49 [sStandardMappings setObject:NSRTFPboardType 50 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_RICH_TEXT]]; 51 [sStandardMappings setObject:NSHTMLPboardType 52 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_HTML]]; 53 [sStandardMappings setObject:NSPDFPboardType 54 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_PDF]]; 55 [sStandardMappings setObject:NSURLPboardType 56 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_URL]]; 57 [sStandardMappings setObject:NSPasteboardTypePNG 58 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_PNG]]; 59 [sStandardMappings setObject:(NSString*)kUTTypeJPEG 60 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_JPEG]]; 61 } 62 return sStandardMappings; 63 } 64 65 /* 66 * Convert from a standard NSPasteboard data type to an index in our mapping table. 67 */ 68 jlong indexForFormat(NSString *format) { 69 jlong returnValue = -1; 70 71 NSMutableDictionary *mappingTable = getMappingTable(); 72 NSArray *matchingKeys = [mappingTable allKeysForObject:format]; 73 74 // There should only be one matching key here... 75 if ([matchingKeys count] > 0) { 76 NSNumber *formatID = (NSNumber *)[matchingKeys objectAtIndex:0]; 77 returnValue = [formatID longValue]; 78 } 79 80 // If we don't recognize the format, but it's a Java "custom" format register it 81 if (returnValue == -1 && ([format hasPrefix:@"JAVA_DATAFLAVOR:"]) ) { 82 returnValue = registerFormatWithPasteboard(format); 83 } 84 85 return returnValue; 86 } 87 88 /* 89 * Inverse of above -- given a long int index, get the matching data format NSString. 90 */ 91 NSString *formatForIndex(jlong inFormatCode) { 92 return [getMappingTable() objectForKey:[NSNumber numberWithLong:inFormatCode]]; 93 } 94 95 jlong registerFormatWithPasteboard(NSString *format) { 96 NSMutableDictionary *mappingTable = getMappingTable(); 97 NSUInteger nextID = [mappingTable count] + 1; 98 [mappingTable setObject:format forKey:[NSNumber numberWithLong:nextID]]; 99 return nextID; 100 } 101 102 103 /* 104 * Class: sun_lwawt_macosx_CDataTransferer 105 * Method: registerFormatWithPasteboard 106 * Signature: (Ljava/lang/String;)J 107 */ 108 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CDataTransferer_registerFormatWithPasteboard 109 (JNIEnv *env, jobject jthis, jstring newformat) 110 { 111 jlong returnValue = -1; 112 JNF_COCOA_ENTER(env); 113 returnValue = registerFormatWithPasteboard(JNFJavaToNSString(env, newformat)); 114 JNF_COCOA_EXIT(env); 115 return returnValue; 116 } 117 118 /* 119 * Class: sun_lwawt_macosx_CDataTransferer 120 * Method: formatForIndex 121 * Signature: (J)Ljava/lang/String; 122 */ 123 JNIEXPORT jstring JNICALL Java_sun_lwawt_macosx_CDataTransferer_formatForIndex 124 (JNIEnv *env, jobject jthis, jlong index) 125 { 126 jstring returnValue = NULL; 127 JNF_COCOA_ENTER(env); 128 returnValue = JNFNSToJavaString(env, formatForIndex(index)); 129 JNF_COCOA_EXIT(env); 130 return returnValue; 131 } 132 133 static jobjectArray CreateJavaFilenameArray(JNIEnv *env, NSArray *filenameArray) 134 { 135 NSUInteger filenameCount = [filenameArray count]; 136 if (filenameCount == 0) return nil; 137 138 // Get the java.lang.String class object: 139 jclass stringClazz = (*env)->FindClass(env, "java/lang/String"); 140 CHECK_NULL_RETURN(stringClazz, nil); 141 jobject jfilenameArray = (*env)->NewObjectArray(env, filenameCount, stringClazz, NULL); // AWT_THREADING Safe (known object) 142 if ((*env)->ExceptionOccurred(env)) { 143 (*env)->ExceptionDescribe(env); 144 (*env)->ExceptionClear(env); 145 return nil; 146 } 147 if (!jfilenameArray) { 148 NSLog(@"CDataTransferer_CreateJavaFilenameArray: couldn't create jfilenameArray."); 149 return nil; 150 } 151 (*env)->DeleteLocalRef(env, stringClazz); 152 153 // Iterate through all the filenames: 154 NSUInteger i; 155 for (i = 0; i < filenameCount; i++) { 156 NSMutableString *stringVal = [[NSMutableString alloc] initWithString:[filenameArray objectAtIndex:i]]; 157 CFStringNormalize((CFMutableStringRef)stringVal, kCFStringNormalizationFormC); 158 const char* stringBytes = [stringVal UTF8String]; 159 160 // Create a Java String: 161 jstring string = (*env)->NewStringUTF(env, stringBytes); 162 if ((*env)->ExceptionOccurred(env)) { 163 (*env)->ExceptionDescribe(env); 164 (*env)->ExceptionClear(env); 165 continue; 166 } 167 if (!string) { 168 NSLog(@"CDataTransferer_CreateJavaFilenameArray: couldn't create jstring[%lu] for [%@].", (unsigned long) i, stringVal); 169 continue; 170 } 171 172 // Set the Java array element with our String: 173 (*env)->SetObjectArrayElement(env, jfilenameArray, i, string); 174 if ((*env)->ExceptionOccurred(env)) { 175 (*env)->ExceptionDescribe(env); 176 (*env)->ExceptionClear(env); 177 continue; 178 } 179 180 // Release local String reference: 181 (*env)->DeleteLocalRef(env, string); 182 } 183 184 return jfilenameArray; 185 } 186 187 /* 188 * Class: sun_lwawt_macosx_CDataTransferer 189 * Method: draqQueryFile 190 * Signature: ([B)[Ljava/lang/String; 191 */ 192 JNIEXPORT jobjectArray JNICALL 193 Java_sun_lwawt_macosx_CDataTransferer_nativeDragQueryFile 194 (JNIEnv *env, jclass clazz, jbyteArray jbytearray) 195 { 196 // Decodes a byte array into a set of String filenames. 197 // bytes here is an XML property list containing all of the filenames in the drag. 198 // Parse the XML list into strings and return an array of Java strings matching all of the 199 // files in the list. 200 201 jobjectArray jreturnArray = NULL; 202 203 JNF_COCOA_ENTER(env); 204 // Get byte array elements: 205 jboolean isCopy; 206 jbyte* jbytes = (*env)->GetByteArrayElements(env, jbytearray, &isCopy); 207 if (jbytes == NULL) { 208 return NULL; 209 } 210 211 // Wrap jbytes in an NSData object: 212 jsize jbytesLength = (*env)->GetArrayLength(env, jbytearray); 213 NSData *xmlData = [NSData dataWithBytesNoCopy:jbytes length:jbytesLength freeWhenDone:NO]; 214 215 // Create a property list from the Java data: 216 NSString *errString = nil; 217 NSPropertyListFormat plistFormat = 0; 218 id plist = [NSPropertyListSerialization propertyListFromData:xmlData mutabilityOption:NSPropertyListImmutable 219 format:&plistFormat errorDescription:&errString]; 220 221 // The property list must be an array of strings: 222 if (plist == nil || [plist isKindOfClass:[NSArray class]] == FALSE) { 223 NSLog(@"CDataTransferer_dragQueryFile: plist not a valid NSArray (error %@):\n%@", errString, plist); 224 (*env)->ReleaseByteArrayElements(env, jbytearray, jbytes, JNI_ABORT); 225 return NULL; 226 } 227 228 // Transfer all string items from the plistArray to filenameArray. This wouldn't be necessary 229 // if we could trust the array to contain all valid elements but this way we'll be sure. 230 NSArray *plistArray = (NSArray *)plist; 231 NSUInteger plistItemCount = [plistArray count]; 232 NSMutableArray *filenameArray = [[NSMutableArray alloc] initWithCapacity:plistItemCount]; 233 234 NSUInteger i; 235 for (i = 0; i < plistItemCount; i++) { 236 // Filenames must be strings: 237 id idVal = [plistArray objectAtIndex:i]; 238 if ([idVal isKindOfClass:[NSString class]] == FALSE) { 239 NSLog(@"CDataTransferer_dragQueryFile: plist[%lu] not an NSString:\n%@", (unsigned long) i, idVal); 240 continue; 241 } 242 243 [filenameArray addObject:idVal]; 244 } 245 246 // Convert our array of filenames into a Java array of String filenames: 247 jreturnArray = CreateJavaFilenameArray(env, filenameArray); 248 249 [filenameArray release]; 250 251 // We're done with the jbytes (backing the plist/plistArray): 252 (*env)->ReleaseByteArrayElements(env, jbytearray, jbytes, JNI_ABORT); 253 JNF_COCOA_EXIT(env); 254 return jreturnArray; 255 } --- EOF ---