src/share/classes/sun/awt/datatransfer/DataTransferer.java

Print this page
rev 9830 : 8039642: Fix raw and unchecked warnings in sun.awt.*
Reviewed-by: darcy, prr


 337 
 338     /**
 339      * Returns whether this flavor is a text type which supports the
 340      * 'charset' parameter.
 341      */
 342     public static boolean isFlavorCharsetTextType(DataFlavor flavor) {
 343         // Although stringFlavor doesn't actually support the charset
 344         // parameter (because its primary MIME type is not "text"), it should
 345         // be treated as though it does. stringFlavor is semantically
 346         // equivalent to "text/plain" data.
 347         if (DataFlavor.stringFlavor.equals(flavor)) {
 348             return true;
 349         }
 350 
 351         if (!"text".equals(flavor.getPrimaryType()) ||
 352             !doesSubtypeSupportCharset(flavor))
 353         {
 354             return false;
 355         }
 356 
 357         Class rep_class = flavor.getRepresentationClass();
 358 
 359         if (flavor.isRepresentationClassReader() ||
 360             String.class.equals(rep_class) ||
 361             flavor.isRepresentationClassCharBuffer() ||
 362             char[].class.equals(rep_class))
 363         {
 364             return true;
 365         }
 366 
 367         if (!(flavor.isRepresentationClassInputStream() ||
 368               flavor.isRepresentationClassByteBuffer() ||
 369               byte[].class.equals(rep_class))) {
 370             return false;
 371         }
 372 
 373         String charset = flavor.getParameter("charset");
 374 
 375         return (charset != null)
 376             ? DataTransferer.isEncodingSupported(charset)
 377             : true; // null equals default encoding which is always supported


 709                     break;
 710                 }
 711             }
 712         }
 713 
 714         return flavorMap;
 715     }
 716 
 717     /**
 718      * Returns a Set of all DataFlavors for which
 719      * 1) a mapping from at least one of the specified formats exists in the
 720      * specified map and
 721      * 2) the data translation for this mapping can be performed by the data
 722      * transfer subsystem.
 723      *
 724      * @param formats the data formats
 725      * @param map the FlavorTable which contains mappings between
 726      *            DataFlavors and data formats
 727      * @throws NullPointerException if formats or map is <code>null</code>
 728      */
 729     public Set getFlavorsForFormatsAsSet(long[] formats, FlavorTable map) {
 730         Set<DataFlavor> flavorSet = new HashSet<>(formats.length);
 731 
 732         for (long format : formats) {
 733             List<DataFlavor> flavors = map.getFlavorsForNative(getNativeForFormat(format));
 734             for (DataFlavor flavor : flavors) {
 735                 // Don't explicitly test for String, since it is just a special
 736                 // case of Serializable
 737                 if (flavor.isFlavorTextType() ||
 738                         flavor.isFlavorJavaFileListType() ||
 739                         DataFlavor.imageFlavor.equals(flavor) ||
 740                         flavor.isRepresentationClassSerializable() ||
 741                         flavor.isRepresentationClassInputStream() ||
 742                         flavor.isRepresentationClassRemote()) {
 743                     flavorSet.add(flavor);
 744                 }
 745             }
 746         }
 747 
 748         return flavorSet;
 749     }


1100 
1101             Image image = (Image)obj;
1102             byte[] bytes = imageToPlatformBytes(image, format);
1103 
1104             if (bytes == null) {
1105                 throw new IOException("Data translation failed: " +
1106                     "cannot convert java image to native format");
1107             }
1108             return bytes;
1109         }
1110 
1111         byte[] theByteArray = null;
1112 
1113         // Target data is a file list. Source data must be a
1114         // java.util.List which contains java.io.File or String instances.
1115         if (isFileFormat(format)) {
1116             if (!DataFlavor.javaFileListFlavor.equals(flavor)) {
1117                 throw new IOException("data translation failed");
1118             }
1119 
1120             final List list = (List)obj;
1121 
1122             final ProtectionDomain userProtectionDomain = getUserProtectionDomain(contents);
1123 
1124             final ArrayList<String> fileList = castToFiles(list, userProtectionDomain);
1125 
1126             try (ByteArrayOutputStream bos = convertFileListToBytes(fileList)) {
1127                 theByteArray = bos.toByteArray();
1128             }
1129 
1130         // Target data is a URI list. Source data must be a
1131         // java.util.List which contains java.io.File or String instances.
1132         } else if (isURIListFormat(format)) {
1133             if (!DataFlavor.javaFileListFlavor.equals(flavor)) {
1134                 throw new IOException("data translation failed");
1135             }
1136             String nat = getNativeForFormat(format);
1137             String targetCharset = null;
1138             if (nat != null) {
1139                 try {
1140                     targetCharset = new DataFlavor(nat).getParameter("charset");
1141                 } catch (ClassNotFoundException cnfe) {
1142                     throw new IOException(cnfe);
1143                 }
1144             }
1145             if (targetCharset == null) {
1146                 targetCharset = "UTF-8";
1147             }
1148             final List list = (List)obj;
1149             final ProtectionDomain userProtectionDomain = getUserProtectionDomain(contents);
1150             final ArrayList<String> fileList = castToFiles(list, userProtectionDomain);
1151             final ArrayList<String> uriList = new ArrayList<>(fileList.size());
1152             for (String fileObject : fileList) {
1153                 final URI uri = new File(fileObject).toURI();
1154                 // Some implementations are fussy about the number of slashes (file:///path/to/file is best)
1155                 try {
1156                     uriList.add(new URI(uri.getScheme(), "", uri.getPath(), uri.getFragment()).toString());
1157                 } catch (URISyntaxException uriSyntaxException) {
1158                     throw new IOException(uriSyntaxException);
1159                   }
1160               }
1161 
1162             byte[] eoln = "\r\n".getBytes(targetCharset);
1163 
1164             try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
1165                 for (String uri : uriList) {
1166                     byte[] bytes = uri.getBytes(targetCharset);
1167                     bos.write(bytes, 0, bytes.length);
1168                     bos.write(eoln, 0, eoln.length);


1273     private static ProtectionDomain getUserProtectionDomain(Transferable contents) {
1274         return contents.getClass().getProtectionDomain();
1275     }
1276 
1277     private boolean isForbiddenToRead (File file, ProtectionDomain protectionDomain)
1278     {
1279         if (null == protectionDomain) {
1280             return false;
1281         }
1282         try {
1283             FilePermission filePermission =
1284                     new FilePermission(file.getCanonicalPath(), "read, delete");
1285             if (protectionDomain.implies(filePermission)) {
1286                 return false;
1287             }
1288         } catch (IOException e) {}
1289 
1290         return true;
1291     }
1292 
1293     private ArrayList<String> castToFiles(final List files,
1294                                           final ProtectionDomain userProtectionDomain) throws IOException {
1295         try {
1296             return AccessController.doPrivileged((PrivilegedExceptionAction<ArrayList<String>>) () -> {
1297                 ArrayList<String> fileList = new ArrayList<>();
1298                 for (Object fileObject : files)
1299                 {
1300                     File file = castToFile(fileObject);
1301                     if (file != null &&
1302                         (null == System.getSecurityManager() ||
1303                         !(isFileInWebstartedCache(file) ||
1304                         isForbiddenToRead(file, userProtectionDomain))))
1305                     {
1306                         fileList.add(file.getCanonicalPath());
1307                     }
1308                 }
1309                 return fileList;
1310             });
1311         } catch (PrivilegedActionException pae) {
1312             throw new IOException(pae.getMessage());
1313         }


1651      */
1652     private Object translateStreamToInputStream
1653         (InputStream str, DataFlavor flavor, long format,
1654          Transferable localeTransferable) throws IOException
1655     {
1656         if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
1657             str = new ReencodingInputStream
1658                 (str, format, DataTransferer.getTextCharset(flavor),
1659                  localeTransferable);
1660         }
1661 
1662         return constructFlavoredObject(str, flavor, InputStream.class);
1663     }
1664 
1665     /**
1666      * We support representations which are exactly of the specified Class,
1667      * and also arbitrary Objects which have a constructor which takes an
1668      * instance of the Class as its sole parameter.
1669      */
1670     private Object constructFlavoredObject(Object arg, DataFlavor flavor,
1671                                            Class clazz)
1672         throws IOException
1673     {
1674         final Class<?> dfrc = flavor.getRepresentationClass();
1675 
1676         if (clazz.equals(dfrc)) {
1677             return arg; // simple case
1678         } else {
1679             Constructor[] constructors;
1680 
1681             try {
1682                 constructors = AccessController.doPrivileged(
1683                         (PrivilegedAction<Constructor[]>) dfrc::getConstructors);
1684             } catch (SecurityException se) {
1685                 throw new IOException(se.getMessage());
1686             }
1687 
1688             Constructor constructor = Stream.of(constructors)
1689                     .filter(c -> Modifier.isPublic(c.getModifiers()))
1690                     .filter(c -> {
1691                         Class[] ptypes = c.getParameterTypes();
1692                         return ptypes != null
1693                                 && ptypes.length == 1
1694                                 && clazz.equals(ptypes[0]);
1695                     })
1696                     .findFirst()
1697                     .orElseThrow(() ->
1698                             new IOException("can't find <init>(L"+ clazz + ";)V for class: " + dfrc.getName()));
1699 
1700             try {
1701                 return constructor.newInstance(arg);
1702             } catch (Exception e) {
1703                 throw new IOException(e.getMessage());
1704             }
1705         }
1706     }
1707 
1708     /**
1709      * Used for decoding and reencoding an InputStream on demand so that we
1710      * can strip NUL terminators and perform EOLN search-and-replace.
1711      */


1900 
1901     /**
1902      * Translates either a byte array or an input stream which contain
1903      * platform-specific image data in the given format into an Image.
1904      */
1905 
1906 
1907     protected abstract Image platformImageBytesToImage(
1908         byte[] bytes,long format) throws IOException;
1909 
1910     /**
1911      * Translates either a byte array or an input stream which contain
1912      * an image data in the given standard format into an Image.
1913      *
1914      * @param mimeType image MIME type, such as: image/png, image/jpeg, image/gif
1915      */
1916     protected Image standardImageBytesToImage(
1917         byte[] bytes, String mimeType) throws IOException
1918     {
1919 
1920         Iterator readerIterator = ImageIO.getImageReadersByMIMEType(mimeType);

1921 
1922         if (!readerIterator.hasNext()) {
1923             throw new IOException("No registered service provider can decode " +
1924                                   " an image from " + mimeType);
1925         }
1926 
1927         IOException ioe = null;
1928 
1929         while (readerIterator.hasNext()) {
1930             ImageReader imageReader = (ImageReader)readerIterator.next();
1931             try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) {
1932                 try (ImageInputStream imageInputStream = ImageIO.createImageInputStream(bais)) {
1933                     ImageReadParam param = imageReader.getDefaultReadParam();
1934                     imageReader.setInput(imageInputStream, true, true);
1935                     BufferedImage bufferedImage = imageReader.read(imageReader.getMinIndex(), param);
1936                     if (bufferedImage != null) {
1937                         return bufferedImage;
1938                     }
1939                 } finally {
1940                     imageReader.dispose();
1941                 }
1942             } catch (IOException e) {
1943                 ioe = e;
1944                 continue;
1945             }
1946         }
1947 
1948         if (ioe == null) {
1949             ioe = new IOException("Registered service providers failed to decode"
1950                                   + " an image from " + mimeType);


1953         throw ioe;
1954     }
1955 
1956     /**
1957      * Translates a Java Image into a byte array which contains platform-
1958      * specific image data in the given format.
1959      */
1960     protected abstract byte[] imageToPlatformBytes(Image image, long format)
1961       throws IOException;
1962 
1963     /**
1964      * Translates a Java Image into a byte array which contains
1965      * an image data in the given standard format.
1966      *
1967      * @param mimeType image MIME type, such as: image/png, image/jpeg
1968      */
1969     protected byte[] imageToStandardBytes(Image image, String mimeType)
1970       throws IOException {
1971         IOException originalIOE = null;
1972 
1973         Iterator writerIterator = ImageIO.getImageWritersByMIMEType(mimeType);

1974 
1975         if (!writerIterator.hasNext()) {
1976             throw new IOException("No registered service provider can encode " +
1977                                   " an image to " + mimeType);
1978         }
1979 
1980         if (image instanceof RenderedImage) {
1981             // Try to encode the original image.
1982             try {
1983                 return imageToStandardBytesImpl((RenderedImage)image, mimeType);
1984             } catch (IOException ioe) {
1985                 originalIOE = ioe;
1986             }
1987         }
1988 
1989         // Retry with a BufferedImage.
1990         int width = 0;
1991         int height = 0;
1992         if (image instanceof ToolkitImage) {
1993             ImageRepresentation ir = ((ToolkitImage)image).getImageRep();


2012             g.drawImage(image, 0, 0, width, height, null);
2013         } finally {
2014             g.dispose();
2015         }
2016 
2017         try {
2018             return imageToStandardBytesImpl(bufferedImage, mimeType);
2019         } catch (IOException ioe) {
2020             if (originalIOE != null) {
2021                 throw originalIOE;
2022             } else {
2023                 throw ioe;
2024             }
2025         }
2026     }
2027 
2028     byte[] imageToStandardBytesImpl(RenderedImage renderedImage,
2029                                               String mimeType)
2030         throws IOException {
2031 
2032         Iterator writerIterator = ImageIO.getImageWritersByMIMEType(mimeType);

2033 
2034         ImageTypeSpecifier typeSpecifier =
2035             new ImageTypeSpecifier(renderedImage);
2036 
2037         ByteArrayOutputStream baos = new ByteArrayOutputStream();
2038         IOException ioe = null;
2039 
2040         while (writerIterator.hasNext()) {
2041             ImageWriter imageWriter = (ImageWriter)writerIterator.next();
2042             ImageWriterSpi writerSpi = imageWriter.getOriginatingProvider();
2043 
2044             if (!writerSpi.canEncodeImage(typeSpecifier)) {
2045                 continue;
2046             }
2047 
2048             try {
2049                 try (ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(baos)) {
2050                     imageWriter.setOutput(imageOutputStream);
2051                     imageWriter.write(renderedImage);
2052                     imageOutputStream.flush();
2053                 }
2054             } catch (IOException e) {
2055                 imageWriter.dispose();
2056                 baos.reset();
2057                 ioe = e;
2058                 continue;
2059             }
2060 
2061             imageWriter.dispose();


2105                 return ret;
2106             } else {
2107                 str1 = new ByteArrayInputStream(arr1);
2108                 str2 = (InputStream)obj2;
2109             }
2110         } else {
2111             str1 = (InputStream)obj1;
2112             if (obj2 instanceof byte[]) {
2113                 str2 = new ByteArrayInputStream((byte[])obj2);
2114             } else {
2115                 str2 = (InputStream)obj2;
2116             }
2117         }
2118 
2119         return new SequenceInputStream(str1, str2);
2120     }
2121 
2122     public byte[] convertData(final Object source,
2123                               final Transferable contents,
2124                               final long format,
2125                               final Map formatMap,
2126                               final boolean isToolkitThread)
2127         throws IOException
2128     {
2129         byte[] ret = null;
2130 
2131         /*
2132          * If the current thread is the Toolkit thread we should post a
2133          * Runnable to the event dispatch thread associated with source Object,
2134          * since translateTransferable() calls Transferable.getTransferData()
2135          * that may contain client code.
2136          */
2137         if (isToolkitThread) try {
2138             final Stack<byte[]> stack = new Stack<>();
2139             final Runnable dataConverter = new Runnable() {
2140                 // Guard against multiple executions.
2141                 private boolean done = false;
2142                 public void run() {
2143                     if (done) {
2144                         return;
2145                     }
2146                     byte[] data = null;
2147                     try {
2148                         DataFlavor flavor = (DataFlavor)formatMap.get(format);
2149                         if (flavor != null) {
2150                             data = translateTransferable(contents, flavor, format);
2151                         }
2152                     } catch (Exception e) {
2153                         e.printStackTrace();
2154                         data = null;
2155                     }
2156                     try {
2157                         getToolkitThreadBlockedHandler().lock();
2158                         stack.push(data);
2159                         getToolkitThreadBlockedHandler().exit();
2160                     } finally {
2161                         getToolkitThreadBlockedHandler().unlock();
2162                         done = true;
2163                     }
2164                 }
2165             };
2166 
2167             final AppContext appContext = SunToolkit.targetToAppContext(source);
2168 
2169             getToolkitThreadBlockedHandler().lock();
2170 
2171             if (appContext != null) {
2172                 appContext.put(DATA_CONVERTER_KEY, dataConverter);
2173             }
2174 
2175             SunToolkit.executeOnEventHandlerThread(source, dataConverter);
2176 
2177             while (stack.empty()) {
2178                 getToolkitThreadBlockedHandler().enter();
2179             }
2180 
2181             if (appContext != null) {
2182                 appContext.remove(DATA_CONVERTER_KEY);
2183             }
2184 
2185             ret = stack.pop();
2186         } finally {
2187             getToolkitThreadBlockedHandler().unlock();
2188         } else {
2189             DataFlavor flavor = (DataFlavor)formatMap.get(format);
2190             if (flavor != null) {
2191                 ret = translateTransferable(contents, flavor, format);
2192             }
2193         }
2194 
2195         return ret;
2196     }
2197 
2198     public void processDataConversionRequests() {
2199         if (EventQueue.isDispatchThread()) {
2200             AppContext appContext = AppContext.getAppContext();
2201             getToolkitThreadBlockedHandler().lock();
2202             try {
2203                 Runnable dataConverter =
2204                     (Runnable)appContext.get(DATA_CONVERTER_KEY);
2205                 if (dataConverter != null) {
2206                     dataConverter.run();
2207                     appContext.remove(DATA_CONVERTER_KEY);
2208                 }
2209             } finally {


2218     /**
2219      * Helper function to reduce a Map with Long keys to a long array.
2220      * <p>
2221      * The map keys are sorted according to the native formats preference
2222      * order.
2223      */
2224     public static long[] keysToLongArray(SortedMap<Long, ?> map) {
2225         Set<Long> keySet = map.keySet();
2226         long[] retval = new long[keySet.size()];
2227         int i = 0;
2228         for (Iterator<Long> iter = keySet.iterator(); iter.hasNext(); i++) {
2229             retval[i] = iter.next();
2230         }
2231         return retval;
2232     }
2233 
2234     /**
2235      * Helper function to convert a Set of DataFlavors to a sorted array.
2236      * The array will be sorted according to <code>DataFlavorComparator</code>.
2237      */
2238     public static DataFlavor[] setToSortedDataFlavorArray(Set flavorsSet) {
2239         DataFlavor[] flavors = new DataFlavor[flavorsSet.size()];
2240         flavorsSet.toArray(flavors);
2241         final Comparator<DataFlavor> comparator =
2242                 new DataFlavorComparator(IndexedComparator.SELECT_WORST);
2243         Arrays.sort(flavors, comparator);
2244         return flavors;
2245     }
2246 
2247     /**
2248      * Helper function to convert an InputStream to a byte[] array.
2249      */
2250     protected static byte[] inputStreamToByteArray(InputStream str)
2251         throws IOException
2252     {
2253         try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
2254             int len = 0;
2255             byte[] buf = new byte[8192];
2256 
2257             while ((len = str.read(buf)) != -1) {
2258                 baos.write(buf, 0, len);


2581 
2582         public DataFlavorComparator(boolean order) {
2583             super(order);
2584 
2585             charsetComparator = new CharsetComparator(order);
2586         }
2587 
2588         public int compare(DataFlavor obj1, DataFlavor obj2) {
2589             DataFlavor flavor1 = order == SELECT_BEST ? obj1 : obj2;
2590             DataFlavor flavor2 = order == SELECT_BEST ? obj2 : obj1;
2591 
2592             if (flavor1.equals(flavor2)) {
2593                 return 0;
2594             }
2595 
2596             int comp = 0;
2597 
2598             String primaryType1 = flavor1.getPrimaryType();
2599             String subType1 = flavor1.getSubType();
2600             String mimeType1 = primaryType1 + "/" + subType1;
2601             Class class1 = flavor1.getRepresentationClass();
2602 
2603             String primaryType2 = flavor2.getPrimaryType();
2604             String subType2 = flavor2.getSubType();
2605             String mimeType2 = primaryType2 + "/" + subType2;
2606             Class class2 = flavor2.getRepresentationClass();
2607 
2608             if (flavor1.isFlavorTextType() && flavor2.isFlavorTextType()) {
2609                 // First, compare MIME types
2610                 comp = compareIndices(textTypes, mimeType1, mimeType2,
2611                                       UNKNOWN_OBJECT_LOSES);
2612                 if (comp != 0) {
2613                     return comp;
2614                 }
2615 
2616                 // Only need to test one flavor because they both have the
2617                 // same MIME type. Also don't need to worry about accidentally
2618                 // passing stringFlavor because either
2619                 //   1. Both flavors are stringFlavor, in which case the
2620                 //      equality test at the top of the function succeeded.
2621                 //   2. Only one flavor is stringFlavor, in which case the MIME
2622                 //      type comparison returned a non-zero value.
2623                 if (doesSubtypeSupportCharset(flavor1)) {
2624                     // Next, prefer the decoded text representations of Reader,
2625                     // String, CharBuffer, and [C, in that order.
2626                     comp = compareIndices(decodedTextRepresentations, class1,




 337 
 338     /**
 339      * Returns whether this flavor is a text type which supports the
 340      * 'charset' parameter.
 341      */
 342     public static boolean isFlavorCharsetTextType(DataFlavor flavor) {
 343         // Although stringFlavor doesn't actually support the charset
 344         // parameter (because its primary MIME type is not "text"), it should
 345         // be treated as though it does. stringFlavor is semantically
 346         // equivalent to "text/plain" data.
 347         if (DataFlavor.stringFlavor.equals(flavor)) {
 348             return true;
 349         }
 350 
 351         if (!"text".equals(flavor.getPrimaryType()) ||
 352             !doesSubtypeSupportCharset(flavor))
 353         {
 354             return false;
 355         }
 356 
 357         Class<?> rep_class = flavor.getRepresentationClass();
 358 
 359         if (flavor.isRepresentationClassReader() ||
 360             String.class.equals(rep_class) ||
 361             flavor.isRepresentationClassCharBuffer() ||
 362             char[].class.equals(rep_class))
 363         {
 364             return true;
 365         }
 366 
 367         if (!(flavor.isRepresentationClassInputStream() ||
 368               flavor.isRepresentationClassByteBuffer() ||
 369               byte[].class.equals(rep_class))) {
 370             return false;
 371         }
 372 
 373         String charset = flavor.getParameter("charset");
 374 
 375         return (charset != null)
 376             ? DataTransferer.isEncodingSupported(charset)
 377             : true; // null equals default encoding which is always supported


 709                     break;
 710                 }
 711             }
 712         }
 713 
 714         return flavorMap;
 715     }
 716 
 717     /**
 718      * Returns a Set of all DataFlavors for which
 719      * 1) a mapping from at least one of the specified formats exists in the
 720      * specified map and
 721      * 2) the data translation for this mapping can be performed by the data
 722      * transfer subsystem.
 723      *
 724      * @param formats the data formats
 725      * @param map the FlavorTable which contains mappings between
 726      *            DataFlavors and data formats
 727      * @throws NullPointerException if formats or map is <code>null</code>
 728      */
 729     public Set<DataFlavor> getFlavorsForFormatsAsSet(long[] formats, FlavorTable map) {
 730         Set<DataFlavor> flavorSet = new HashSet<>(formats.length);
 731 
 732         for (long format : formats) {
 733             List<DataFlavor> flavors = map.getFlavorsForNative(getNativeForFormat(format));
 734             for (DataFlavor flavor : flavors) {
 735                 // Don't explicitly test for String, since it is just a special
 736                 // case of Serializable
 737                 if (flavor.isFlavorTextType() ||
 738                         flavor.isFlavorJavaFileListType() ||
 739                         DataFlavor.imageFlavor.equals(flavor) ||
 740                         flavor.isRepresentationClassSerializable() ||
 741                         flavor.isRepresentationClassInputStream() ||
 742                         flavor.isRepresentationClassRemote()) {
 743                     flavorSet.add(flavor);
 744                 }
 745             }
 746         }
 747 
 748         return flavorSet;
 749     }


1100 
1101             Image image = (Image)obj;
1102             byte[] bytes = imageToPlatformBytes(image, format);
1103 
1104             if (bytes == null) {
1105                 throw new IOException("Data translation failed: " +
1106                     "cannot convert java image to native format");
1107             }
1108             return bytes;
1109         }
1110 
1111         byte[] theByteArray = null;
1112 
1113         // Target data is a file list. Source data must be a
1114         // java.util.List which contains java.io.File or String instances.
1115         if (isFileFormat(format)) {
1116             if (!DataFlavor.javaFileListFlavor.equals(flavor)) {
1117                 throw new IOException("data translation failed");
1118             }
1119 
1120             final List<?> list = (List<?>)obj;
1121 
1122             final ProtectionDomain userProtectionDomain = getUserProtectionDomain(contents);
1123 
1124             final ArrayList<String> fileList = castToFiles(list, userProtectionDomain);
1125 
1126             try (ByteArrayOutputStream bos = convertFileListToBytes(fileList)) {
1127                 theByteArray = bos.toByteArray();
1128             }
1129 
1130         // Target data is a URI list. Source data must be a
1131         // java.util.List which contains java.io.File or String instances.
1132         } else if (isURIListFormat(format)) {
1133             if (!DataFlavor.javaFileListFlavor.equals(flavor)) {
1134                 throw new IOException("data translation failed");
1135             }
1136             String nat = getNativeForFormat(format);
1137             String targetCharset = null;
1138             if (nat != null) {
1139                 try {
1140                     targetCharset = new DataFlavor(nat).getParameter("charset");
1141                 } catch (ClassNotFoundException cnfe) {
1142                     throw new IOException(cnfe);
1143                 }
1144             }
1145             if (targetCharset == null) {
1146                 targetCharset = "UTF-8";
1147             }
1148             final List<?> list = (List<?>)obj;
1149             final ProtectionDomain userProtectionDomain = getUserProtectionDomain(contents);
1150             final ArrayList<String> fileList = castToFiles(list, userProtectionDomain);
1151             final ArrayList<String> uriList = new ArrayList<>(fileList.size());
1152             for (String fileObject : fileList) {
1153                 final URI uri = new File(fileObject).toURI();
1154                 // Some implementations are fussy about the number of slashes (file:///path/to/file is best)
1155                 try {
1156                     uriList.add(new URI(uri.getScheme(), "", uri.getPath(), uri.getFragment()).toString());
1157                 } catch (URISyntaxException uriSyntaxException) {
1158                     throw new IOException(uriSyntaxException);
1159                   }
1160               }
1161 
1162             byte[] eoln = "\r\n".getBytes(targetCharset);
1163 
1164             try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
1165                 for (String uri : uriList) {
1166                     byte[] bytes = uri.getBytes(targetCharset);
1167                     bos.write(bytes, 0, bytes.length);
1168                     bos.write(eoln, 0, eoln.length);


1273     private static ProtectionDomain getUserProtectionDomain(Transferable contents) {
1274         return contents.getClass().getProtectionDomain();
1275     }
1276 
1277     private boolean isForbiddenToRead (File file, ProtectionDomain protectionDomain)
1278     {
1279         if (null == protectionDomain) {
1280             return false;
1281         }
1282         try {
1283             FilePermission filePermission =
1284                     new FilePermission(file.getCanonicalPath(), "read, delete");
1285             if (protectionDomain.implies(filePermission)) {
1286                 return false;
1287             }
1288         } catch (IOException e) {}
1289 
1290         return true;
1291     }
1292 
1293     private ArrayList<String> castToFiles(final List<?> files,
1294                                           final ProtectionDomain userProtectionDomain) throws IOException {
1295         try {
1296             return AccessController.doPrivileged((PrivilegedExceptionAction<ArrayList<String>>) () -> {
1297                 ArrayList<String> fileList = new ArrayList<>();
1298                 for (Object fileObject : files)
1299                 {
1300                     File file = castToFile(fileObject);
1301                     if (file != null &&
1302                         (null == System.getSecurityManager() ||
1303                         !(isFileInWebstartedCache(file) ||
1304                         isForbiddenToRead(file, userProtectionDomain))))
1305                     {
1306                         fileList.add(file.getCanonicalPath());
1307                     }
1308                 }
1309                 return fileList;
1310             });
1311         } catch (PrivilegedActionException pae) {
1312             throw new IOException(pae.getMessage());
1313         }


1651      */
1652     private Object translateStreamToInputStream
1653         (InputStream str, DataFlavor flavor, long format,
1654          Transferable localeTransferable) throws IOException
1655     {
1656         if (isFlavorCharsetTextType(flavor) && isTextFormat(format)) {
1657             str = new ReencodingInputStream
1658                 (str, format, DataTransferer.getTextCharset(flavor),
1659                  localeTransferable);
1660         }
1661 
1662         return constructFlavoredObject(str, flavor, InputStream.class);
1663     }
1664 
1665     /**
1666      * We support representations which are exactly of the specified Class,
1667      * and also arbitrary Objects which have a constructor which takes an
1668      * instance of the Class as its sole parameter.
1669      */
1670     private Object constructFlavoredObject(Object arg, DataFlavor flavor,
1671                                            Class<?> clazz)
1672         throws IOException
1673     {
1674         final Class<?> dfrc = flavor.getRepresentationClass();
1675 
1676         if (clazz.equals(dfrc)) {
1677             return arg; // simple case
1678         } else {
1679             Constructor<?>[] constructors;
1680 
1681             try {
1682                 constructors = AccessController.doPrivileged(
1683                         (PrivilegedAction<Constructor<?>[]>) dfrc::getConstructors);
1684             } catch (SecurityException se) {
1685                 throw new IOException(se.getMessage());
1686             }
1687 
1688             Constructor<?> constructor = Stream.of(constructors)
1689                     .filter(c -> Modifier.isPublic(c.getModifiers()))
1690                     .filter(c -> {
1691                         Class<?>[] ptypes = c.getParameterTypes();
1692                         return ptypes != null
1693                                 && ptypes.length == 1
1694                                 && clazz.equals(ptypes[0]);
1695                     })
1696                     .findFirst()
1697                     .orElseThrow(() ->
1698                             new IOException("can't find <init>(L"+ clazz + ";)V for class: " + dfrc.getName()));
1699 
1700             try {
1701                 return constructor.newInstance(arg);
1702             } catch (Exception e) {
1703                 throw new IOException(e.getMessage());
1704             }
1705         }
1706     }
1707 
1708     /**
1709      * Used for decoding and reencoding an InputStream on demand so that we
1710      * can strip NUL terminators and perform EOLN search-and-replace.
1711      */


1900 
1901     /**
1902      * Translates either a byte array or an input stream which contain
1903      * platform-specific image data in the given format into an Image.
1904      */
1905 
1906 
1907     protected abstract Image platformImageBytesToImage(
1908         byte[] bytes,long format) throws IOException;
1909 
1910     /**
1911      * Translates either a byte array or an input stream which contain
1912      * an image data in the given standard format into an Image.
1913      *
1914      * @param mimeType image MIME type, such as: image/png, image/jpeg, image/gif
1915      */
1916     protected Image standardImageBytesToImage(
1917         byte[] bytes, String mimeType) throws IOException
1918     {
1919 
1920         Iterator<ImageReader> readerIterator =
1921             ImageIO.getImageReadersByMIMEType(mimeType);
1922 
1923         if (!readerIterator.hasNext()) {
1924             throw new IOException("No registered service provider can decode " +
1925                                   " an image from " + mimeType);
1926         }
1927 
1928         IOException ioe = null;
1929 
1930         while (readerIterator.hasNext()) {
1931             ImageReader imageReader = readerIterator.next();
1932             try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) {
1933                 try (ImageInputStream imageInputStream = ImageIO.createImageInputStream(bais)) {
1934                     ImageReadParam param = imageReader.getDefaultReadParam();
1935                     imageReader.setInput(imageInputStream, true, true);
1936                     BufferedImage bufferedImage = imageReader.read(imageReader.getMinIndex(), param);
1937                     if (bufferedImage != null) {
1938                         return bufferedImage;
1939                     }
1940                 } finally {
1941                     imageReader.dispose();
1942                 }
1943             } catch (IOException e) {
1944                 ioe = e;
1945                 continue;
1946             }
1947         }
1948 
1949         if (ioe == null) {
1950             ioe = new IOException("Registered service providers failed to decode"
1951                                   + " an image from " + mimeType);


1954         throw ioe;
1955     }
1956 
1957     /**
1958      * Translates a Java Image into a byte array which contains platform-
1959      * specific image data in the given format.
1960      */
1961     protected abstract byte[] imageToPlatformBytes(Image image, long format)
1962       throws IOException;
1963 
1964     /**
1965      * Translates a Java Image into a byte array which contains
1966      * an image data in the given standard format.
1967      *
1968      * @param mimeType image MIME type, such as: image/png, image/jpeg
1969      */
1970     protected byte[] imageToStandardBytes(Image image, String mimeType)
1971       throws IOException {
1972         IOException originalIOE = null;
1973 
1974         Iterator<ImageWriter> writerIterator =
1975             ImageIO.getImageWritersByMIMEType(mimeType);
1976 
1977         if (!writerIterator.hasNext()) {
1978             throw new IOException("No registered service provider can encode " +
1979                                   " an image to " + mimeType);
1980         }
1981 
1982         if (image instanceof RenderedImage) {
1983             // Try to encode the original image.
1984             try {
1985                 return imageToStandardBytesImpl((RenderedImage)image, mimeType);
1986             } catch (IOException ioe) {
1987                 originalIOE = ioe;
1988             }
1989         }
1990 
1991         // Retry with a BufferedImage.
1992         int width = 0;
1993         int height = 0;
1994         if (image instanceof ToolkitImage) {
1995             ImageRepresentation ir = ((ToolkitImage)image).getImageRep();


2014             g.drawImage(image, 0, 0, width, height, null);
2015         } finally {
2016             g.dispose();
2017         }
2018 
2019         try {
2020             return imageToStandardBytesImpl(bufferedImage, mimeType);
2021         } catch (IOException ioe) {
2022             if (originalIOE != null) {
2023                 throw originalIOE;
2024             } else {
2025                 throw ioe;
2026             }
2027         }
2028     }
2029 
2030     byte[] imageToStandardBytesImpl(RenderedImage renderedImage,
2031                                               String mimeType)
2032         throws IOException {
2033 
2034         Iterator<ImageWriter> writerIterator =
2035             ImageIO.getImageWritersByMIMEType(mimeType);
2036 
2037         ImageTypeSpecifier typeSpecifier =
2038             new ImageTypeSpecifier(renderedImage);
2039 
2040         ByteArrayOutputStream baos = new ByteArrayOutputStream();
2041         IOException ioe = null;
2042 
2043         while (writerIterator.hasNext()) {
2044             ImageWriter imageWriter = writerIterator.next();
2045             ImageWriterSpi writerSpi = imageWriter.getOriginatingProvider();
2046 
2047             if (!writerSpi.canEncodeImage(typeSpecifier)) {
2048                 continue;
2049             }
2050 
2051             try {
2052                 try (ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(baos)) {
2053                     imageWriter.setOutput(imageOutputStream);
2054                     imageWriter.write(renderedImage);
2055                     imageOutputStream.flush();
2056                 }
2057             } catch (IOException e) {
2058                 imageWriter.dispose();
2059                 baos.reset();
2060                 ioe = e;
2061                 continue;
2062             }
2063 
2064             imageWriter.dispose();


2108                 return ret;
2109             } else {
2110                 str1 = new ByteArrayInputStream(arr1);
2111                 str2 = (InputStream)obj2;
2112             }
2113         } else {
2114             str1 = (InputStream)obj1;
2115             if (obj2 instanceof byte[]) {
2116                 str2 = new ByteArrayInputStream((byte[])obj2);
2117             } else {
2118                 str2 = (InputStream)obj2;
2119             }
2120         }
2121 
2122         return new SequenceInputStream(str1, str2);
2123     }
2124 
2125     public byte[] convertData(final Object source,
2126                               final Transferable contents,
2127                               final long format,
2128                               final Map<Long, DataFlavor> formatMap,
2129                               final boolean isToolkitThread)
2130         throws IOException
2131     {
2132         byte[] ret = null;
2133 
2134         /*
2135          * If the current thread is the Toolkit thread we should post a
2136          * Runnable to the event dispatch thread associated with source Object,
2137          * since translateTransferable() calls Transferable.getTransferData()
2138          * that may contain client code.
2139          */
2140         if (isToolkitThread) try {
2141             final Stack<byte[]> stack = new Stack<>();
2142             final Runnable dataConverter = new Runnable() {
2143                 // Guard against multiple executions.
2144                 private boolean done = false;
2145                 public void run() {
2146                     if (done) {
2147                         return;
2148                     }
2149                     byte[] data = null;
2150                     try {
2151                         DataFlavor flavor = formatMap.get(format);
2152                         if (flavor != null) {
2153                             data = translateTransferable(contents, flavor, format);
2154                         }
2155                     } catch (Exception e) {
2156                         e.printStackTrace();
2157                         data = null;
2158                     }
2159                     try {
2160                         getToolkitThreadBlockedHandler().lock();
2161                         stack.push(data);
2162                         getToolkitThreadBlockedHandler().exit();
2163                     } finally {
2164                         getToolkitThreadBlockedHandler().unlock();
2165                         done = true;
2166                     }
2167                 }
2168             };
2169 
2170             final AppContext appContext = SunToolkit.targetToAppContext(source);
2171 
2172             getToolkitThreadBlockedHandler().lock();
2173 
2174             if (appContext != null) {
2175                 appContext.put(DATA_CONVERTER_KEY, dataConverter);
2176             }
2177 
2178             SunToolkit.executeOnEventHandlerThread(source, dataConverter);
2179 
2180             while (stack.empty()) {
2181                 getToolkitThreadBlockedHandler().enter();
2182             }
2183 
2184             if (appContext != null) {
2185                 appContext.remove(DATA_CONVERTER_KEY);
2186             }
2187 
2188             ret = stack.pop();
2189         } finally {
2190             getToolkitThreadBlockedHandler().unlock();
2191         } else {
2192             DataFlavor flavor = formatMap.get(format);
2193             if (flavor != null) {
2194                 ret = translateTransferable(contents, flavor, format);
2195             }
2196         }
2197 
2198         return ret;
2199     }
2200 
2201     public void processDataConversionRequests() {
2202         if (EventQueue.isDispatchThread()) {
2203             AppContext appContext = AppContext.getAppContext();
2204             getToolkitThreadBlockedHandler().lock();
2205             try {
2206                 Runnable dataConverter =
2207                     (Runnable)appContext.get(DATA_CONVERTER_KEY);
2208                 if (dataConverter != null) {
2209                     dataConverter.run();
2210                     appContext.remove(DATA_CONVERTER_KEY);
2211                 }
2212             } finally {


2221     /**
2222      * Helper function to reduce a Map with Long keys to a long array.
2223      * <p>
2224      * The map keys are sorted according to the native formats preference
2225      * order.
2226      */
2227     public static long[] keysToLongArray(SortedMap<Long, ?> map) {
2228         Set<Long> keySet = map.keySet();
2229         long[] retval = new long[keySet.size()];
2230         int i = 0;
2231         for (Iterator<Long> iter = keySet.iterator(); iter.hasNext(); i++) {
2232             retval[i] = iter.next();
2233         }
2234         return retval;
2235     }
2236 
2237     /**
2238      * Helper function to convert a Set of DataFlavors to a sorted array.
2239      * The array will be sorted according to <code>DataFlavorComparator</code>.
2240      */
2241     public static DataFlavor[] setToSortedDataFlavorArray(Set<DataFlavor> flavorsSet) {
2242         DataFlavor[] flavors = new DataFlavor[flavorsSet.size()];
2243         flavorsSet.toArray(flavors);
2244         final Comparator<DataFlavor> comparator =
2245                 new DataFlavorComparator(IndexedComparator.SELECT_WORST);
2246         Arrays.sort(flavors, comparator);
2247         return flavors;
2248     }
2249 
2250     /**
2251      * Helper function to convert an InputStream to a byte[] array.
2252      */
2253     protected static byte[] inputStreamToByteArray(InputStream str)
2254         throws IOException
2255     {
2256         try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
2257             int len = 0;
2258             byte[] buf = new byte[8192];
2259 
2260             while ((len = str.read(buf)) != -1) {
2261                 baos.write(buf, 0, len);


2584 
2585         public DataFlavorComparator(boolean order) {
2586             super(order);
2587 
2588             charsetComparator = new CharsetComparator(order);
2589         }
2590 
2591         public int compare(DataFlavor obj1, DataFlavor obj2) {
2592             DataFlavor flavor1 = order == SELECT_BEST ? obj1 : obj2;
2593             DataFlavor flavor2 = order == SELECT_BEST ? obj2 : obj1;
2594 
2595             if (flavor1.equals(flavor2)) {
2596                 return 0;
2597             }
2598 
2599             int comp = 0;
2600 
2601             String primaryType1 = flavor1.getPrimaryType();
2602             String subType1 = flavor1.getSubType();
2603             String mimeType1 = primaryType1 + "/" + subType1;
2604             Class<?> class1 = flavor1.getRepresentationClass();
2605 
2606             String primaryType2 = flavor2.getPrimaryType();
2607             String subType2 = flavor2.getSubType();
2608             String mimeType2 = primaryType2 + "/" + subType2;
2609             Class<?> class2 = flavor2.getRepresentationClass();
2610 
2611             if (flavor1.isFlavorTextType() && flavor2.isFlavorTextType()) {
2612                 // First, compare MIME types
2613                 comp = compareIndices(textTypes, mimeType1, mimeType2,
2614                                       UNKNOWN_OBJECT_LOSES);
2615                 if (comp != 0) {
2616                     return comp;
2617                 }
2618 
2619                 // Only need to test one flavor because they both have the
2620                 // same MIME type. Also don't need to worry about accidentally
2621                 // passing stringFlavor because either
2622                 //   1. Both flavors are stringFlavor, in which case the
2623                 //      equality test at the top of the function succeeded.
2624                 //   2. Only one flavor is stringFlavor, in which case the MIME
2625                 //      type comparison returned a non-zero value.
2626                 if (doesSubtypeSupportCharset(flavor1)) {
2627                     // Next, prefer the decoded text representations of Reader,
2628                     // String, CharBuffer, and [C, in that order.
2629                     comp = compareIndices(decodedTextRepresentations, class1,