1 /* 2 * Copyright (c) 2011, 2015, 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 "jni_util.h" 30 31 #import <JavaNativeFoundation/JavaNativeFoundation.h> 32 33 34 // ***** NOTE ***** This dictionary corresponds to the static array predefinedClipboardNames 35 // in CDataTransferer.java. 36 NSMutableDictionary *sStandardMappings = nil; 37 38 NSMutableDictionary *getMappingTable() { 39 if (sStandardMappings == nil) { 40 sStandardMappings = [[NSMutableDictionary alloc] init]; 41 [sStandardMappings setObject:NSStringPboardType 42 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_STRING]]; 43 [sStandardMappings setObject:NSFilenamesPboardType 44 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_FILE]]; 45 [sStandardMappings setObject:NSTIFFPboardType 46 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_TIFF]]; 47 [sStandardMappings setObject:NSRTFPboardType 48 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_RICH_TEXT]]; 49 [sStandardMappings setObject:NSHTMLPboardType 50 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_HTML]]; 51 [sStandardMappings setObject:NSPDFPboardType 52 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_PDF]]; 53 [sStandardMappings setObject:NSURLPboardType 54 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_URL]]; 55 [sStandardMappings setObject:NSPasteboardTypePNG 56 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_PNG]]; 57 [sStandardMappings setObject:(NSString*)kUTTypeJPEG 58 forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_JPEG]]; 59 } 60 return sStandardMappings; 61 } 62 63 /* 64 * Convert from a standard NSPasteboard data type to an index in our mapping table. 65 */ 66 jlong indexForFormat(NSString *format) { 67 jlong returnValue = -1; 68 69 NSMutableDictionary *mappingTable = getMappingTable(); 70 NSArray *matchingKeys = [mappingTable allKeysForObject:format]; 71 72 // There should only be one matching key here... 73 if ([matchingKeys count] > 0) { 74 NSNumber *formatID = (NSNumber *)[matchingKeys objectAtIndex:0]; 75 returnValue = [formatID longValue]; 76 } 77 78 // If we don't recognize the format, but it's a Java "custom" format register it 79 if (returnValue == -1 && ([format hasPrefix:@"JAVA_DATAFLAVOR:"]) ) { 80 returnValue = registerFormatWithPasteboard(format); 81 } 82 83 return returnValue; 84 } 85 86 /* 87 * Inverse of above -- given a long int index, get the matching data format NSString. 88 */ 89 NSString *formatForIndex(jlong inFormatCode) { 90 return [getMappingTable() objectForKey:[NSNumber numberWithLong:inFormatCode]]; 91 } 92 93 jlong registerFormatWithPasteboard(NSString *format) { 94 NSMutableDictionary *mappingTable = getMappingTable(); 95 NSUInteger nextID = [mappingTable count] + 1; 96 [mappingTable setObject:format forKey:[NSNumber numberWithLong:nextID]]; 97 return nextID; 98 } 99 100 101 /* 102 * Class: sun_lwawt_macosx_CDataTransferer 103 * Method: registerFormatWithPasteboard 104 * Signature: (Ljava/lang/String;)J 105 */ 106 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CDataTransferer_registerFormatWithPasteboard 107 (JNIEnv *env, jobject jthis, jstring newformat) 108 { 109 jlong returnValue = -1; 110 JNF_COCOA_ENTER(env); 111 returnValue = registerFormatWithPasteboard(JNFJavaToNSString(env, newformat)); 112 JNF_COCOA_EXIT(env); 113 return returnValue; 114 } 115 116 /* 117 * Class: sun_lwawt_macosx_CDataTransferer 118 * Method: formatForIndex 119 * Signature: (J)Ljava/lang/String; 120 */ 121 JNIEXPORT jstring JNICALL Java_sun_lwawt_macosx_CDataTransferer_formatForIndex 122 (JNIEnv *env, jobject jthis, jlong index) 123 { 124 jstring returnValue = NULL; 125 JNF_COCOA_ENTER(env); 126 returnValue = JNFNSToJavaString(env, formatForIndex(index)); 127 JNF_COCOA_EXIT(env); 128 return returnValue; 129 } 130 131 static jobjectArray CreateJavaFilenameArray(JNIEnv *env, NSArray *filenameArray) 132 { 133 NSUInteger filenameCount = [filenameArray count]; 134 if (filenameCount == 0) return nil; 135 136 // Get the java.lang.String class object: 137 jclass stringClazz = (*env)->FindClass(env, "java/lang/String"); 138 CHECK_NULL_RETURN(stringClazz, nil); 139 jobject jfilenameArray = (*env)->NewObjectArray(env, filenameCount, stringClazz, NULL); // AWT_THREADING Safe (known object) 140 if ((*env)->ExceptionOccurred(env)) { 141 (*env)->ExceptionDescribe(env); 142 (*env)->ExceptionClear(env); 143 return nil; 144 } 145 if (!jfilenameArray) { 146 NSLog(@"CDataTransferer_CreateJavaFilenameArray: couldn't create jfilenameArray."); 147 return nil; 148 } 149 (*env)->DeleteLocalRef(env, stringClazz); 150 151 // Iterate through all the filenames: 152 NSUInteger i; 153 for (i = 0; i < filenameCount; i++) { 154 NSMutableString *stringVal = [[NSMutableString alloc] initWithString:[filenameArray objectAtIndex:i]]; 155 CFStringNormalize((CFMutableStringRef)stringVal, kCFStringNormalizationFormC); 156 const char* stringBytes = [stringVal UTF8String]; 157 158 // Create a Java String: 159 jstring string = (*env)->NewStringUTF(env, stringBytes); 160 if ((*env)->ExceptionOccurred(env)) { 161 (*env)->ExceptionDescribe(env); 162 (*env)->ExceptionClear(env); 163 continue; 164 } 165 if (!string) { 166 NSLog(@"CDataTransferer_CreateJavaFilenameArray: couldn't create jstring[%lu] for [%@].", (unsigned long) i, stringVal); 167 continue; 168 } 169 170 // Set the Java array element with our String: 171 (*env)->SetObjectArrayElement(env, jfilenameArray, i, string); 172 if ((*env)->ExceptionOccurred(env)) { 173 (*env)->ExceptionDescribe(env); 174 (*env)->ExceptionClear(env); 175 continue; 176 } 177 178 // Release local String reference: 179 (*env)->DeleteLocalRef(env, string); 180 } 181 182 return jfilenameArray; 183 } 184 185 /* 186 * Class: sun_lwawt_macosx_CDataTransferer 187 * Method: draqQueryFile 188 * Signature: ([B)[Ljava/lang/String; 189 */ 190 JNIEXPORT jobjectArray JNICALL 191 Java_sun_lwawt_macosx_CDataTransferer_nativeDragQueryFile 192 (JNIEnv *env, jclass clazz, jbyteArray jbytearray) 193 { 194 // Decodes a byte array into a set of String filenames. 195 // bytes here is an XML property list containing all of the filenames in the drag. 196 // Parse the XML list into strings and return an array of Java strings matching all of the 197 // files in the list. 198 199 jobjectArray jreturnArray = NULL; 200 201 JNF_COCOA_ENTER(env); 202 // Get byte array elements: 203 jboolean isCopy; 204 jbyte* jbytes = (*env)->GetByteArrayElements(env, jbytearray, &isCopy); 205 if (jbytes == NULL) { 206 return NULL; 207 } 208 209 // Wrap jbytes in an NSData object: 210 jsize jbytesLength = (*env)->GetArrayLength(env, jbytearray); 211 NSData *xmlData = [NSData dataWithBytesNoCopy:jbytes length:jbytesLength freeWhenDone:NO]; 212 213 // Create a property list from the Java data: 214 NSString *errString = nil; 215 NSPropertyListFormat plistFormat = 0; 216 id plist = [NSPropertyListSerialization propertyListFromData:xmlData mutabilityOption:NSPropertyListImmutable 217 format:&plistFormat errorDescription:&errString]; 218 219 // The property list must be an array of strings: 220 if (plist == nil || [plist isKindOfClass:[NSArray class]] == FALSE) { 221 NSLog(@"CDataTransferer_dragQueryFile: plist not a valid NSArray (error %@):\n%@", errString, plist); 222 (*env)->ReleaseByteArrayElements(env, jbytearray, jbytes, JNI_ABORT); 223 return NULL; 224 } 225 226 // Transfer all string items from the plistArray to filenameArray. This wouldn't be necessary 227 // if we could trust the array to contain all valid elements but this way we'll be sure. 228 NSArray *plistArray = (NSArray *)plist; 229 NSUInteger plistItemCount = [plistArray count]; 230 NSMutableArray *filenameArray = [[NSMutableArray alloc] initWithCapacity:plistItemCount]; 231 232 NSUInteger i; 233 for (i = 0; i < plistItemCount; i++) { 234 // Filenames must be strings: 235 id idVal = [plistArray objectAtIndex:i]; 236 if ([idVal isKindOfClass:[NSString class]] == FALSE) { 237 NSLog(@"CDataTransferer_dragQueryFile: plist[%lu] not an NSString:\n%@", (unsigned long) i, idVal); 238 continue; 239 } 240 241 [filenameArray addObject:idVal]; 242 } 243 244 // Convert our array of filenames into a Java array of String filenames: 245 jreturnArray = CreateJavaFilenameArray(env, filenameArray); 246 247 [filenameArray release]; 248 249 // We're done with the jbytes (backing the plist/plistArray): 250 (*env)->ReleaseByteArrayElements(env, jbytearray, jbytes, JNI_ABORT); 251 JNF_COCOA_EXIT(env); 252 return jreturnArray; 253 } --- EOF ---