--- old/make/src/classes/build/tools/module/boot.modules 2015-01-13 17:31:17.029324400 +0400 +++ new/make/src/classes/build/tools/module/boot.modules 2015-01-13 17:31:15.943262300 +0400 @@ -1,4 +1,5 @@ java.base +java.datatransfer java.desktop java.activation java.annotations.common --- old/src/java.desktop/macosx/classes/sun/datatransfer/resources/flavormap.properties 2015-01-13 17:31:37.574499600 +0400 +++ /dev/null 2015-01-13 17:31:38.000000000 +0400 @@ -1,76 +0,0 @@ -# -# This properties file is used to initialize the default -# java.awt.datatransfer.SystemFlavorMap. It contains the Mac OS X platform-specific, -# default mappings between common Mac OS X selection atoms and platform-independent -# MIME type strings, which will be converted into -# java.awt.datatransfer.DataFlavors. -# -# The standard format is: -# -# =,, ... -# -# should be a string identifier that the native platform will -# recognize as a valid data format. should specify both a MIME -# primary type and a MIME subtype separated by a '/'. The MIME type may include -# parameters, where each parameter is a key/value pair separated by '=', and -# where each parameter to the MIME type is separated by a ';'. -# -# Because SystemFlavorMap implements FlavorTable, developers are free to -# duplicate DataFlavor values and set multiple values for a single native by -# separating them with ",". If a mapping contains a duplicate key or value, -# earlier mappings which included this key or value will be preferred. -# -# Mappings whose values specify DataFlavors with primary MIME types of -# "text", and which support the charset parameter, should specify the exact -# format in which the native platform expects the data. The "charset" -# parameter specifies the char to byte encoding, the "eoln" parameter -# specifies the end-of-line marker, and the "terminators" parameter specifies -# the number of terminating NUL bytes. Note that "eoln" and "terminators" -# are not standardized MIME type parameters. They are specific to this file -# format ONLY. They will not appear in any of the DataFlavors returned by the -# SystemFlavorMap at the Java level. -# -# If the "charset" parameter is omitted, or has zero length, the platform -# default encoding is assumed. If the "eoln" parameter is omitted, or has -# zero length, "\n" is assumed. If the "terminators" parameter is omitted, -# or has a value less than zero, zero is assumed. -# -# Upon initialization, the data transfer subsystem will record the specified -# details of the native text format, but the default SystemFlavorMap will -# present a large set of synthesized DataFlavors which map, in both -# directions, to the native. After receiving data from the application in one -# of the synthetic DataFlavors, the data transfer subsystem will transform -# the data stream into the format specified in this file before passing the -# transformed stream to the native system. -# -# Mappings whose values specify DataFlavors with primary MIME types of -# "text", but which do not support the charset parameter, will be treated as -# opaque, 8-bit data. They will not undergo any transformation process, and -# any "charset", "eoln", or "terminators" parameters specified in this file -# will be ignored. -# -# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of -# text flavors which support the charset parameter. - -UTF8_STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 - -# The COMPOUND_TEXT support for inter-client text transfer is disabled by -# default. The reason is that many native applications prefer this format over -# other native text formats, but are unable to decode the textual data in this -# format properly. This results in java-to-native text transfer failures. -# To enable the COMPOUND_TEXT support for this JRE installation uncomment -# the line below. - -# COMPOUND_TEXT=text/plain;charset=x-compound-text;eoln="\n";terminators=0 - -TEXT=text/plain;eoln="\n";terminators=0 -STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 -FILE_NAME=application/x-java-file-list;class=java.util.List -text/uri-list=application/x-java-file-list;class=java.util.List -PNG=image/x-java-image;class=java.awt.Image -JFIF=image/x-java-image;class=java.awt.Image -TIFF=image/x-java-image;class=java.awt.Image -RICH_TEXT=text/rtf -HTML=text/html;charset=utf-8;eoln="\r\n";terminators=1 -URL=application/x-java-url;class=java.net.URL,\ - text/uri-list;eoln="\r\n";terminators=1 --- /dev/null 2015-01-13 17:31:38.000000000 +0400 +++ new/src/java.datatransfer/macosx/classes/sun/datatransfer/resources/flavormap.properties 2015-01-13 17:31:37.000466700 +0400 @@ -0,0 +1,76 @@ +# +# This properties file is used to initialize the default +# java.awt.datatransfer.SystemFlavorMap. It contains the Mac OS X platform-specific, +# default mappings between common Mac OS X selection atoms and platform-independent +# MIME type strings, which will be converted into +# java.awt.datatransfer.DataFlavors. +# +# The standard format is: +# +# =,, ... +# +# should be a string identifier that the native platform will +# recognize as a valid data format. should specify both a MIME +# primary type and a MIME subtype separated by a '/'. The MIME type may include +# parameters, where each parameter is a key/value pair separated by '=', and +# where each parameter to the MIME type is separated by a ';'. +# +# Because SystemFlavorMap implements FlavorTable, developers are free to +# duplicate DataFlavor values and set multiple values for a single native by +# separating them with ",". If a mapping contains a duplicate key or value, +# earlier mappings which included this key or value will be preferred. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", and which support the charset parameter, should specify the exact +# format in which the native platform expects the data. The "charset" +# parameter specifies the char to byte encoding, the "eoln" parameter +# specifies the end-of-line marker, and the "terminators" parameter specifies +# the number of terminating NUL bytes. Note that "eoln" and "terminators" +# are not standardized MIME type parameters. They are specific to this file +# format ONLY. They will not appear in any of the DataFlavors returned by the +# SystemFlavorMap at the Java level. +# +# If the "charset" parameter is omitted, or has zero length, the platform +# default encoding is assumed. If the "eoln" parameter is omitted, or has +# zero length, "\n" is assumed. If the "terminators" parameter is omitted, +# or has a value less than zero, zero is assumed. +# +# Upon initialization, the data transfer subsystem will record the specified +# details of the native text format, but the default SystemFlavorMap will +# present a large set of synthesized DataFlavors which map, in both +# directions, to the native. After receiving data from the application in one +# of the synthetic DataFlavors, the data transfer subsystem will transform +# the data stream into the format specified in this file before passing the +# transformed stream to the native system. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", but which do not support the charset parameter, will be treated as +# opaque, 8-bit data. They will not undergo any transformation process, and +# any "charset", "eoln", or "terminators" parameters specified in this file +# will be ignored. +# +# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of +# text flavors which support the charset parameter. + +UTF8_STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 + +# The COMPOUND_TEXT support for inter-client text transfer is disabled by +# default. The reason is that many native applications prefer this format over +# other native text formats, but are unable to decode the textual data in this +# format properly. This results in java-to-native text transfer failures. +# To enable the COMPOUND_TEXT support for this JRE installation uncomment +# the line below. + +# COMPOUND_TEXT=text/plain;charset=x-compound-text;eoln="\n";terminators=0 + +TEXT=text/plain;eoln="\n";terminators=0 +STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 +FILE_NAME=application/x-java-file-list;class=java.util.List +text/uri-list=application/x-java-file-list;class=java.util.List +PNG=image/x-java-image;class=java.awt.Image +JFIF=image/x-java-image;class=java.awt.Image +TIFF=image/x-java-image;class=java.awt.Image +RICH_TEXT=text/rtf +HTML=text/html;charset=utf-8;eoln="\r\n";terminators=1 +URL=application/x-java-url;class=java.net.URL,\ + text/uri-list;eoln="\r\n";terminators=1 --- old/src/java.desktop/share/classes/java/awt/datatransfer/Clipboard.java 2015-01-13 17:31:44.118873900 +0400 +++ /dev/null 2015-01-13 17:31:46.000000000 +0400 @@ -1,352 +0,0 @@ -/* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.awt.datatransfer; - -import sun.datatransfer.DataFlavorUtil; - -import java.util.Objects; -import java.util.Set; -import java.util.HashSet; -import java.util.Arrays; - -import java.io.IOException; - -/** - * A class that implements a mechanism to transfer data using - * cut/copy/paste operations. - *

- * {@link FlavorListener}s may be registered on an instance of the - * Clipboard class to be notified about changes to the set of - * {@link DataFlavor}s available on this clipboard (see - * {@link #addFlavorListener}). - * - * @see java.awt.Toolkit#getSystemClipboard - * @see java.awt.Toolkit#getSystemSelection - * - * @author Amy Fowler - * @author Alexander Gerasimov - */ -public class Clipboard { - - String name; - - /** - * The owner of the clipboard. - */ - protected ClipboardOwner owner; - /** - * Contents of the clipboard. - */ - protected Transferable contents; - - /** - * An aggregate of flavor listeners registered on this local clipboard. - * - * @since 1.5 - */ - private Set flavorListeners; - - /** - * A set of DataFlavors that is available on - * this local clipboard. It is used for tracking changes - * of DataFlavors available on this clipboard. - * - * @since 1.5 - */ - private Set currentDataFlavors; - - /** - * Creates a clipboard object. - * @param name for the clipboard - * @see java.awt.Toolkit#getSystemClipboard - */ - public Clipboard(String name) { - this.name = name; - } - - /** - * Returns the name of this clipboard object. - * @return the name of this clipboard object - * - * @see java.awt.Toolkit#getSystemClipboard - */ - public String getName() { - return name; - } - - /** - * Sets the current contents of the clipboard to the specified - * transferable object and registers the specified clipboard owner - * as the owner of the new contents. - *

- * If there is an existing owner different from the argument - * owner, that owner is notified that it no longer - * holds ownership of the clipboard contents via an invocation - * of ClipboardOwner.lostOwnership() on that owner. - * An implementation of setContents() is free not - * to invoke lostOwnership() directly from this method. - * For example, lostOwnership() may be invoked later on - * a different thread. The same applies to FlavorListeners - * registered on this clipboard. - *

- * The method throws IllegalStateException if the clipboard - * is currently unavailable. For example, on some platforms, the system - * clipboard is unavailable while it is accessed by another application. - * - * @param contents the transferable object representing the - * clipboard content - * @param owner the object which owns the clipboard content - * @throws IllegalStateException if the clipboard is currently unavailable - * @see java.awt.Toolkit#getSystemClipboard - */ - public synchronized void setContents(Transferable contents, ClipboardOwner owner) { - final ClipboardOwner oldOwner = this.owner; - final Transferable oldContents = this.contents; - - this.owner = owner; - this.contents = contents; - - if (oldOwner != null && oldOwner != owner) { - DataFlavorUtil.getDesktopService().invokeOnEventThread(() -> - oldOwner.lostOwnership(Clipboard.this, oldContents)); - } - fireFlavorsChanged(); - } - - /** - * Returns a transferable object representing the current contents - * of the clipboard. If the clipboard currently has no contents, - * it returns null. The parameter Object requestor is - * not currently used. The method throws - * IllegalStateException if the clipboard is currently - * unavailable. For example, on some platforms, the system clipboard is - * unavailable while it is accessed by another application. - * - * @param requestor the object requesting the clip data (not used) - * @return the current transferable object on the clipboard - * @throws IllegalStateException if the clipboard is currently unavailable - * @see java.awt.Toolkit#getSystemClipboard - */ - public synchronized Transferable getContents(Object requestor) { - return contents; - } - - - /** - * Returns an array of DataFlavors in which the current - * contents of this clipboard can be provided. If there are no - * DataFlavors available, this method returns a zero-length - * array. - * - * @return an array of DataFlavors in which the current - * contents of this clipboard can be provided - * - * @throws IllegalStateException if this clipboard is currently unavailable - * - * @since 1.5 - */ - public DataFlavor[] getAvailableDataFlavors() { - Transferable cntnts = getContents(null); - if (cntnts == null) { - return new DataFlavor[0]; - } - return cntnts.getTransferDataFlavors(); - } - - /** - * Returns whether or not the current contents of this clipboard can be - * provided in the specified DataFlavor. - * - * @param flavor the requested DataFlavor for the contents - * - * @return true if the current contents of this clipboard - * can be provided in the specified DataFlavor; - * false otherwise - * - * @throws NullPointerException if flavor is null - * @throws IllegalStateException if this clipboard is currently unavailable - * - * @since 1.5 - */ - public boolean isDataFlavorAvailable(DataFlavor flavor) { - if (flavor == null) { - throw new NullPointerException("flavor"); - } - - Transferable cntnts = getContents(null); - if (cntnts == null) { - return false; - } - return cntnts.isDataFlavorSupported(flavor); - } - - /** - * Returns an object representing the current contents of this clipboard - * in the specified DataFlavor. - * The class of the object returned is defined by the representation - * class of flavor. - * - * @param flavor the requested DataFlavor for the contents - * - * @return an object representing the current contents of this clipboard - * in the specified DataFlavor - * - * @throws NullPointerException if flavor is null - * @throws IllegalStateException if this clipboard is currently unavailable - * @throws UnsupportedFlavorException if the requested DataFlavor - * is not available - * @throws IOException if the data in the requested DataFlavor - * can not be retrieved - * - * @see DataFlavor#getRepresentationClass - * - * @since 1.5 - */ - public Object getData(DataFlavor flavor) - throws UnsupportedFlavorException, IOException { - if (flavor == null) { - throw new NullPointerException("flavor"); - } - - Transferable cntnts = getContents(null); - if (cntnts == null) { - throw new UnsupportedFlavorException(flavor); - } - return cntnts.getTransferData(flavor); - } - - - /** - * Registers the specified FlavorListener to receive - * FlavorEvents from this clipboard. - * If listener is null, no exception - * is thrown and no action is performed. - * - * @param listener the listener to be added - * - * @see #removeFlavorListener - * @see #getFlavorListeners - * @see FlavorListener - * @see FlavorEvent - * @since 1.5 - */ - public synchronized void addFlavorListener(FlavorListener listener) { - if (listener == null) { - return; - } - - if (flavorListeners == null) { - flavorListeners = new HashSet<>(); - currentDataFlavors = getAvailableDataFlavorSet(); - } - - flavorListeners.add(listener); - } - - /** - * Removes the specified FlavorListener so that it no longer - * receives FlavorEvents from this Clipboard. - * This method performs no function, nor does it throw an exception, if - * the listener specified by the argument was not previously added to this - * Clipboard. - * If listener is null, no exception - * is thrown and no action is performed. - * - * @param listener the listener to be removed - * - * @see #addFlavorListener - * @see #getFlavorListeners - * @see FlavorListener - * @see FlavorEvent - * @since 1.5 - */ - public synchronized void removeFlavorListener(FlavorListener listener) { - if (listener == null || flavorListeners == null) { - return; - } - flavorListeners.remove(listener); - } - - /** - * Returns an array of all the FlavorListeners currently - * registered on this Clipboard. - * - * @return all of this clipboard's FlavorListeners or an empty - * array if no listeners are currently registered - * @see #addFlavorListener - * @see #removeFlavorListener - * @see FlavorListener - * @see FlavorEvent - * @since 1.5 - */ - public synchronized FlavorListener[] getFlavorListeners() { - return flavorListeners == null ? new FlavorListener[0] : - flavorListeners.toArray(new FlavorListener[flavorListeners.size()]); - } - - /** - * Checks change of the DataFlavors and, if necessary, - * notifies all listeners that have registered interest for notification - * on FlavorEvents. - * - * @since 1.5 - */ - private void fireFlavorsChanged() { - if (flavorListeners == null) { - return; - } - - Set prevDataFlavors = currentDataFlavors; - currentDataFlavors = getAvailableDataFlavorSet(); - if (Objects.equals(prevDataFlavors, currentDataFlavors)) { - return; - } - flavorListeners.forEach(listener -> - DataFlavorUtil.getDesktopService().invokeOnEventThread(() -> - listener.flavorsChanged(new FlavorEvent(Clipboard.this)))); - } - - /** - * Returns a set of DataFlavors currently available - * on this clipboard. - * - * @return a set of DataFlavors currently available - * on this clipboard - * - * @since 1.5 - */ - private Set getAvailableDataFlavorSet() { - Set set = new HashSet<>(); - Transferable contents = getContents(null); - if (contents != null) { - DataFlavor[] flavors = contents.getTransferDataFlavors(); - if (flavors != null) { - set.addAll(Arrays.asList(flavors)); - } - } - return set; - } -} --- /dev/null 2015-01-13 17:31:47.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/Clipboard.java 2015-01-13 17:31:42.170762500 +0400 @@ -0,0 +1,352 @@ +/* + * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.awt.datatransfer; + +import sun.datatransfer.DataFlavorUtil; + +import java.util.Objects; +import java.util.Set; +import java.util.HashSet; +import java.util.Arrays; + +import java.io.IOException; + +/** + * A class that implements a mechanism to transfer data using + * cut/copy/paste operations. + *

+ * {@link FlavorListener}s may be registered on an instance of the + * Clipboard class to be notified about changes to the set of + * {@link DataFlavor}s available on this clipboard (see + * {@link #addFlavorListener}). + * + * @see java.awt.Toolkit#getSystemClipboard + * @see java.awt.Toolkit#getSystemSelection + * + * @author Amy Fowler + * @author Alexander Gerasimov + */ +public class Clipboard { + + String name; + + /** + * The owner of the clipboard. + */ + protected ClipboardOwner owner; + /** + * Contents of the clipboard. + */ + protected Transferable contents; + + /** + * An aggregate of flavor listeners registered on this local clipboard. + * + * @since 1.5 + */ + private Set flavorListeners; + + /** + * A set of DataFlavors that is available on + * this local clipboard. It is used for tracking changes + * of DataFlavors available on this clipboard. + * + * @since 1.5 + */ + private Set currentDataFlavors; + + /** + * Creates a clipboard object. + * @param name for the clipboard + * @see java.awt.Toolkit#getSystemClipboard + */ + public Clipboard(String name) { + this.name = name; + } + + /** + * Returns the name of this clipboard object. + * @return the name of this clipboard object + * + * @see java.awt.Toolkit#getSystemClipboard + */ + public String getName() { + return name; + } + + /** + * Sets the current contents of the clipboard to the specified + * transferable object and registers the specified clipboard owner + * as the owner of the new contents. + *

+ * If there is an existing owner different from the argument + * owner, that owner is notified that it no longer + * holds ownership of the clipboard contents via an invocation + * of ClipboardOwner.lostOwnership() on that owner. + * An implementation of setContents() is free not + * to invoke lostOwnership() directly from this method. + * For example, lostOwnership() may be invoked later on + * a different thread. The same applies to FlavorListeners + * registered on this clipboard. + *

+ * The method throws IllegalStateException if the clipboard + * is currently unavailable. For example, on some platforms, the system + * clipboard is unavailable while it is accessed by another application. + * + * @param contents the transferable object representing the + * clipboard content + * @param owner the object which owns the clipboard content + * @throws IllegalStateException if the clipboard is currently unavailable + * @see java.awt.Toolkit#getSystemClipboard + */ + public synchronized void setContents(Transferable contents, ClipboardOwner owner) { + final ClipboardOwner oldOwner = this.owner; + final Transferable oldContents = this.contents; + + this.owner = owner; + this.contents = contents; + + if (oldOwner != null && oldOwner != owner) { + DataFlavorUtil.getDesktopService().invokeOnEventThread(() -> + oldOwner.lostOwnership(Clipboard.this, oldContents)); + } + fireFlavorsChanged(); + } + + /** + * Returns a transferable object representing the current contents + * of the clipboard. If the clipboard currently has no contents, + * it returns null. The parameter Object requestor is + * not currently used. The method throws + * IllegalStateException if the clipboard is currently + * unavailable. For example, on some platforms, the system clipboard is + * unavailable while it is accessed by another application. + * + * @param requestor the object requesting the clip data (not used) + * @return the current transferable object on the clipboard + * @throws IllegalStateException if the clipboard is currently unavailable + * @see java.awt.Toolkit#getSystemClipboard + */ + public synchronized Transferable getContents(Object requestor) { + return contents; + } + + + /** + * Returns an array of DataFlavors in which the current + * contents of this clipboard can be provided. If there are no + * DataFlavors available, this method returns a zero-length + * array. + * + * @return an array of DataFlavors in which the current + * contents of this clipboard can be provided + * + * @throws IllegalStateException if this clipboard is currently unavailable + * + * @since 1.5 + */ + public DataFlavor[] getAvailableDataFlavors() { + Transferable cntnts = getContents(null); + if (cntnts == null) { + return new DataFlavor[0]; + } + return cntnts.getTransferDataFlavors(); + } + + /** + * Returns whether or not the current contents of this clipboard can be + * provided in the specified DataFlavor. + * + * @param flavor the requested DataFlavor for the contents + * + * @return true if the current contents of this clipboard + * can be provided in the specified DataFlavor; + * false otherwise + * + * @throws NullPointerException if flavor is null + * @throws IllegalStateException if this clipboard is currently unavailable + * + * @since 1.5 + */ + public boolean isDataFlavorAvailable(DataFlavor flavor) { + if (flavor == null) { + throw new NullPointerException("flavor"); + } + + Transferable cntnts = getContents(null); + if (cntnts == null) { + return false; + } + return cntnts.isDataFlavorSupported(flavor); + } + + /** + * Returns an object representing the current contents of this clipboard + * in the specified DataFlavor. + * The class of the object returned is defined by the representation + * class of flavor. + * + * @param flavor the requested DataFlavor for the contents + * + * @return an object representing the current contents of this clipboard + * in the specified DataFlavor + * + * @throws NullPointerException if flavor is null + * @throws IllegalStateException if this clipboard is currently unavailable + * @throws UnsupportedFlavorException if the requested DataFlavor + * is not available + * @throws IOException if the data in the requested DataFlavor + * can not be retrieved + * + * @see DataFlavor#getRepresentationClass + * + * @since 1.5 + */ + public Object getData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + if (flavor == null) { + throw new NullPointerException("flavor"); + } + + Transferable cntnts = getContents(null); + if (cntnts == null) { + throw new UnsupportedFlavorException(flavor); + } + return cntnts.getTransferData(flavor); + } + + + /** + * Registers the specified FlavorListener to receive + * FlavorEvents from this clipboard. + * If listener is null, no exception + * is thrown and no action is performed. + * + * @param listener the listener to be added + * + * @see #removeFlavorListener + * @see #getFlavorListeners + * @see FlavorListener + * @see FlavorEvent + * @since 1.5 + */ + public synchronized void addFlavorListener(FlavorListener listener) { + if (listener == null) { + return; + } + + if (flavorListeners == null) { + flavorListeners = new HashSet<>(); + currentDataFlavors = getAvailableDataFlavorSet(); + } + + flavorListeners.add(listener); + } + + /** + * Removes the specified FlavorListener so that it no longer + * receives FlavorEvents from this Clipboard. + * This method performs no function, nor does it throw an exception, if + * the listener specified by the argument was not previously added to this + * Clipboard. + * If listener is null, no exception + * is thrown and no action is performed. + * + * @param listener the listener to be removed + * + * @see #addFlavorListener + * @see #getFlavorListeners + * @see FlavorListener + * @see FlavorEvent + * @since 1.5 + */ + public synchronized void removeFlavorListener(FlavorListener listener) { + if (listener == null || flavorListeners == null) { + return; + } + flavorListeners.remove(listener); + } + + /** + * Returns an array of all the FlavorListeners currently + * registered on this Clipboard. + * + * @return all of this clipboard's FlavorListeners or an empty + * array if no listeners are currently registered + * @see #addFlavorListener + * @see #removeFlavorListener + * @see FlavorListener + * @see FlavorEvent + * @since 1.5 + */ + public synchronized FlavorListener[] getFlavorListeners() { + return flavorListeners == null ? new FlavorListener[0] : + flavorListeners.toArray(new FlavorListener[flavorListeners.size()]); + } + + /** + * Checks change of the DataFlavors and, if necessary, + * notifies all listeners that have registered interest for notification + * on FlavorEvents. + * + * @since 1.5 + */ + private void fireFlavorsChanged() { + if (flavorListeners == null) { + return; + } + + Set prevDataFlavors = currentDataFlavors; + currentDataFlavors = getAvailableDataFlavorSet(); + if (Objects.equals(prevDataFlavors, currentDataFlavors)) { + return; + } + flavorListeners.forEach(listener -> + DataFlavorUtil.getDesktopService().invokeOnEventThread(() -> + listener.flavorsChanged(new FlavorEvent(Clipboard.this)))); + } + + /** + * Returns a set of DataFlavors currently available + * on this clipboard. + * + * @return a set of DataFlavors currently available + * on this clipboard + * + * @since 1.5 + */ + private Set getAvailableDataFlavorSet() { + Set set = new HashSet<>(); + Transferable contents = getContents(null); + if (contents != null) { + DataFlavor[] flavors = contents.getTransferDataFlavors(); + if (flavors != null) { + set.addAll(Arrays.asList(flavors)); + } + } + return set; + } +} --- old/src/java.desktop/share/classes/java/awt/datatransfer/ClipboardOwner.java 2015-01-13 17:31:59.201736600 +0400 +++ /dev/null 2015-01-13 17:32:00.000000000 +0400 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.awt.datatransfer; - -/** - * Defines the interface for classes that will provide data to - * a clipboard. An instance of this interface becomes the owner - * of the contents of a clipboard (clipboard owner) if it is - * passed as an argument to - * {@link java.awt.datatransfer.Clipboard#setContents} method of - * the clipboard and this method returns successfully. - * The instance remains the clipboard owner until another application - * or another object within this application asserts ownership - * of this clipboard. - * - * @see java.awt.datatransfer.Clipboard - * - * @author Amy Fowler - */ - -public interface ClipboardOwner { - - /** - * Notifies this object that it is no longer the clipboard owner. - * This method will be called when another application or another - * object within this application asserts ownership of the clipboard. - * - * @param clipboard the clipboard that is no longer owned - * @param contents the contents which this owner had placed on the clipboard - */ - public void lostOwnership(Clipboard clipboard, Transferable contents); - -} --- /dev/null 2015-01-13 17:32:01.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/ClipboardOwner.java 2015-01-13 17:31:57.417634500 +0400 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.awt.datatransfer; + +/** + * Defines the interface for classes that will provide data to + * a clipboard. An instance of this interface becomes the owner + * of the contents of a clipboard (clipboard owner) if it is + * passed as an argument to + * {@link java.awt.datatransfer.Clipboard#setContents} method of + * the clipboard and this method returns successfully. + * The instance remains the clipboard owner until another application + * or another object within this application asserts ownership + * of this clipboard. + * + * @see java.awt.datatransfer.Clipboard + * + * @author Amy Fowler + */ + +public interface ClipboardOwner { + + /** + * Notifies this object that it is no longer the clipboard owner. + * This method will be called when another application or another + * object within this application asserts ownership of the clipboard. + * + * @param clipboard the clipboard that is no longer owned + * @param contents the contents which this owner had placed on the clipboard + */ + public void lostOwnership(Clipboard clipboard, Transferable contents); + +} --- old/src/java.desktop/share/classes/java/awt/datatransfer/DataFlavor.java 2015-01-13 17:32:09.287313400 +0400 +++ /dev/null 2015-01-13 17:32:17.000000000 +0400 @@ -1,1433 +0,0 @@ -/* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.awt.datatransfer; - -import sun.datatransfer.DataFlavorUtil; -import sun.reflect.misc.ReflectUtil; - -import java.io.ByteArrayInputStream; -import java.io.CharArrayReader; -import java.io.Externalizable; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.ObjectInput; -import java.io.ObjectOutput; -import java.io.OptionalDataException; -import java.io.Reader; -import java.io.StringReader; -import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.util.Arrays; -import java.util.Collections; -import java.util.Objects; - -import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; - -/** - * A {@code DataFlavor} provides meta information about data. {@code DataFlavor} - * is typically used to access data on the clipboard, or during - * a drag and drop operation. - *

- * An instance of {@code DataFlavor} encapsulates a content type as - * defined in RFC 2045 - * and RFC 2046. - * A content type is typically referred to as a MIME type. - *

- * A content type consists of a media type (referred - * to as the primary type), a subtype, and optional parameters. See - * RFC 2045 - * for details on the syntax of a MIME type. - *

- * The JRE data transfer implementation interprets the parameter "class" - * of a MIME type as a representation class. - * The representation class reflects the class of the object being - * transferred. In other words, the representation class is the type of - * object returned by {@link Transferable#getTransferData}. - * For example, the MIME type of {@link #imageFlavor} is - * {@code "image/x-java-image;class=java.awt.Image"}, - * the primary type is {@code image}, the subtype is - * {@code x-java-image}, and the representation class is - * {@code java.awt.Image}. When {@code getTransferData} is invoked - * with a {@code DataFlavor} of {@code imageFlavor}, an instance of - * {@code java.awt.Image} is returned. - * It's important to note that {@code DataFlavor} does no error checking - * against the representation class. It is up to consumers of - * {@code DataFlavor}, such as {@code Transferable}, to honor the representation - * class. - *
- * Note, if you do not specify a representation class when - * creating a {@code DataFlavor}, the default - * representation class is used. See appropriate documentation for - * {@code DataFlavor}'s constructors. - *

- * Also, {@code DataFlavor} instances with the "text" primary - * MIME type may have a "charset" parameter. Refer to - * RFC 2046 and - * {@link #selectBestTextFlavor} for details on "text" MIME types - * and the "charset" parameter. - *

- * Equality of {@code DataFlavors} is determined by the primary type, - * subtype, and representation class. Refer to {@link #equals(DataFlavor)} for - * details. When determining equality, any optional parameters are ignored. - * For example, the following produces two {@code DataFlavors} that - * are considered identical: - *

- *   DataFlavor flavor1 = new DataFlavor(Object.class, "X-test/test; class=<java.lang.Object>; foo=bar");
- *   DataFlavor flavor2 = new DataFlavor(Object.class, "X-test/test; class=<java.lang.Object>; x=y");
- *   // The following returns true.
- *   flavor1.equals(flavor2);
- * 
- * As mentioned, {@code flavor1} and {@code flavor2} are considered identical. - * As such, asking a {@code Transferable} for either {@code DataFlavor} returns - * the same results. - *

- * For more information on using data transfer with Swing see - * the - * How to Use Drag and Drop and Data Transfer, - * section in Java Tutorial. - * - * @author Blake Sullivan - * @author Laurence P. G. Cable - * @author Jeff Dunn - */ -public class DataFlavor implements Externalizable, Cloneable { - - private static final long serialVersionUID = 8367026044764648243L; - private static final Class ioInputStreamClass = InputStream.class; - - /** - * Tries to load a class from: the bootstrap loader, the system loader, - * the context loader (if one is present) and finally the loader specified. - * - * @param className the name of the class to be loaded - * @param fallback the fallback loader - * @return the class loaded - * @exception ClassNotFoundException if class is not found - */ - protected final static Class tryToLoadClass(String className, - ClassLoader fallback) - throws ClassNotFoundException - { - ReflectUtil.checkPackageAccess(className); - try { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(GET_CLASSLOADER_PERMISSION); - } - ClassLoader loader = ClassLoader.getSystemClassLoader(); - try { - // bootstrap class loader and system class loader if present - return Class.forName(className, true, loader); - } - catch (ClassNotFoundException exception) { - // thread context class loader if and only if present - loader = Thread.currentThread().getContextClassLoader(); - if (loader != null) { - try { - return Class.forName(className, true, loader); - } - catch (ClassNotFoundException e) { - // fallback to user's class loader - } - } - } - } catch (SecurityException exception) { - // ignore secured class loaders - } - return Class.forName(className, true, fallback); - } - - /* - * private initializer - */ - static private DataFlavor createConstant(Class rc, String prn) { - try { - return new DataFlavor(rc, prn); - } catch (Exception e) { - return null; - } - } - - /* - * private initializer - */ - static private DataFlavor createConstant(String mt, String prn) { - try { - return new DataFlavor(mt, prn); - } catch (Exception e) { - return null; - } - } - - /* - * private initializer - */ - static private DataFlavor initHtmlDataFlavor(String htmlFlavorType) { - try { - return new DataFlavor ("text/html; class=java.lang.String;document=" + - htmlFlavorType + ";charset=Unicode"); - } catch (Exception e) { - return null; - } - } - - /** - * The DataFlavor representing a Java Unicode String class, - * where: - *

-     *     representationClass = java.lang.String
-     *     mimeType           = "application/x-java-serialized-object"
-     * 
- */ - public static final DataFlavor stringFlavor = createConstant(java.lang.String.class, "Unicode String"); - - /** - * The DataFlavor representing a Java Image class, - * where: - *
-     *     representationClass = java.awt.Image
-     *     mimeType            = "image/x-java-image"
-     * 
- */ - public static final DataFlavor imageFlavor = createConstant("image/x-java-image; class=java.awt.Image", "Image"); - - /** - * The DataFlavor representing plain text with Unicode - * encoding, where: - *
-     *     representationClass = InputStream
-     *     mimeType            = "text/plain; charset=unicode"
-     * 
- * This DataFlavor has been deprecated because - * (1) Its representation is an InputStream, an 8-bit based representation, - * while Unicode is a 16-bit character set; and (2) The charset "unicode" - * is not well-defined. "unicode" implies a particular platform's - * implementation of Unicode, not a cross-platform implementation. - * - * @deprecated as of 1.3. Use DataFlavor.getReaderForText(Transferable) - * instead of Transferable.getTransferData(DataFlavor.plainTextFlavor). - */ - @Deprecated - public static final DataFlavor plainTextFlavor = createConstant("text/plain; charset=unicode; class=java.io.InputStream", "Plain Text"); - - /** - * A MIME Content-Type of application/x-java-serialized-object represents - * a graph of Java object(s) that have been made persistent. - * - * The representation class associated with this DataFlavor - * identifies the Java type of an object returned as a reference - * from an invocation java.awt.datatransfer.getTransferData. - */ - public static final String javaSerializedObjectMimeType = "application/x-java-serialized-object"; - - /** - * To transfer a list of files to/from Java (and the underlying - * platform) a DataFlavor of this type/subtype and - * representation class of java.util.List is used. - * Each element of the list is required/guaranteed to be of type - * java.io.File. - */ - public static final DataFlavor javaFileListFlavor = createConstant("application/x-java-file-list;class=java.util.List", null); - - /** - * To transfer a reference to an arbitrary Java object reference that - * has no associated MIME Content-type, across a Transferable - * interface WITHIN THE SAME JVM, a DataFlavor - * with this type/subtype is used, with a representationClass - * equal to the type of the class/interface being passed across the - * Transferable. - *

- * The object reference returned from - * Transferable.getTransferData for a DataFlavor - * with this MIME Content-Type is required to be - * an instance of the representation Class of the DataFlavor. - */ - public static final String javaJVMLocalObjectMimeType = "application/x-java-jvm-local-objectref"; - - /** - * In order to pass a live link to a Remote object via a Drag and Drop - * ACTION_LINK operation a Mime Content Type of - * application/x-java-remote-object should be used, - * where the representation class of the DataFlavor - * represents the type of the Remote interface to be - * transferred. - */ - public static final String javaRemoteObjectMimeType = "application/x-java-remote-object"; - - /** - * Represents a piece of an HTML markup. The markup consists of the part - * selected on the source side. Therefore some tags in the markup may be - * unpaired. If the flavor is used to represent the data in - * a {@link Transferable} instance, no additional changes will be made. - * This DataFlavor instance represents the same HTML markup as DataFlavor - * instances which content MIME type does not contain document parameter - * and representation class is the String class. - *

-     *     representationClass = String
-     *     mimeType           = "text/html"
-     * 
- */ - public static DataFlavor selectionHtmlFlavor = initHtmlDataFlavor("selection"); - - /** - * Represents a piece of an HTML markup. If possible, the markup received - * from a native system is supplemented with pair tags to be - * a well-formed HTML markup. If the flavor is used to represent the data in - * a {@link Transferable} instance, no additional changes will be made. - *
-     *     representationClass = String
-     *     mimeType           = "text/html"
-     * 
- */ - public static DataFlavor fragmentHtmlFlavor = initHtmlDataFlavor("fragment"); - - /** - * Represents a piece of an HTML markup. If possible, the markup - * received from a native system is supplemented with additional - * tags to make up a well-formed HTML document. If the flavor is used to - * represent the data in a {@link Transferable} instance, - * no additional changes will be made. - *
-     *     representationClass = String
-     *     mimeType           = "text/html"
-     * 
- */ - public static DataFlavor allHtmlFlavor = initHtmlDataFlavor("all"); - - /** - * Constructs a new DataFlavor. This constructor is - * provided only for the purpose of supporting the - * Externalizable interface. It is not - * intended for public (client) use. - * - * @since 1.2 - */ - public DataFlavor() { - super(); - } - - /** - * Constructs a fully specified DataFlavor. - * - * @exception NullPointerException if either primaryType, - * subType or representationClass is null - */ - private DataFlavor(String primaryType, String subType, MimeTypeParameterList params, Class representationClass, String humanPresentableName) { - super(); - if (primaryType == null) { - throw new NullPointerException("primaryType"); - } - if (subType == null) { - throw new NullPointerException("subType"); - } - if (representationClass == null) { - throw new NullPointerException("representationClass"); - } - - if (params == null) params = new MimeTypeParameterList(); - - params.set("class", representationClass.getName()); - - if (humanPresentableName == null) { - humanPresentableName = params.get("humanPresentableName"); - - if (humanPresentableName == null) - humanPresentableName = primaryType + "/" + subType; - } - - try { - mimeType = new MimeType(primaryType, subType, params); - } catch (MimeTypeParseException mtpe) { - throw new IllegalArgumentException("MimeType Parse Exception: " + mtpe.getMessage()); - } - - this.representationClass = representationClass; - this.humanPresentableName = humanPresentableName; - - mimeType.removeParameter("humanPresentableName"); - } - - /** - * Constructs a DataFlavor that represents a Java class. - *

- * The returned DataFlavor will have the following - * characteristics: - *

-     *    representationClass = representationClass
-     *    mimeType            = application/x-java-serialized-object
-     * 
- * @param representationClass the class used to transfer data in this flavor - * @param humanPresentableName the human-readable string used to identify - * this flavor; if this parameter is null - * then the value of the MIME Content Type is used - * @exception NullPointerException if representationClass is null - */ - public DataFlavor(Class representationClass, String humanPresentableName) { - this("application", "x-java-serialized-object", null, representationClass, humanPresentableName); - if (representationClass == null) { - throw new NullPointerException("representationClass"); - } - } - - /** - * Constructs a DataFlavor that represents a - * MimeType. - *

- * The returned DataFlavor will have the following - * characteristics: - *

- * If the mimeType is - * "application/x-java-serialized-object; class=<representation class>", - * the result is the same as calling - * new DataFlavor(Class.forName(<representation class>). - *

- * Otherwise: - *

-     *     representationClass = InputStream
-     *     mimeType            = mimeType
-     * 
- * @param mimeType the string used to identify the MIME type for this flavor; - * if the mimeType does not specify a - * "class=" parameter, or if the class is not successfully - * loaded, then an IllegalArgumentException - * is thrown - * @param humanPresentableName the human-readable string used to identify - * this flavor; if this parameter is null - * then the value of the MIME Content Type is used - * @exception IllegalArgumentException if mimeType is - * invalid or if the class is not successfully loaded - * @exception NullPointerException if mimeType is null - */ - public DataFlavor(String mimeType, String humanPresentableName) { - super(); - if (mimeType == null) { - throw new NullPointerException("mimeType"); - } - try { - initialize(mimeType, humanPresentableName, this.getClass().getClassLoader()); - } catch (MimeTypeParseException mtpe) { - throw new IllegalArgumentException("failed to parse:" + mimeType); - } catch (ClassNotFoundException cnfe) { - throw new IllegalArgumentException("can't find specified class: " + cnfe.getMessage()); - } - } - - /** - * Constructs a DataFlavor that represents a - * MimeType. - *

- * The returned DataFlavor will have the following - * characteristics: - *

- * If the mimeType is - * "application/x-java-serialized-object; class=<representation class>", - * the result is the same as calling - * new DataFlavor(Class.forName(<representation class>). - *

- * Otherwise: - *

-     *     representationClass = InputStream
-     *     mimeType            = mimeType
-     * 
- * @param mimeType the string used to identify the MIME type for this flavor - * @param humanPresentableName the human-readable string used to - * identify this flavor - * @param classLoader the class loader to use - * @exception ClassNotFoundException if the class is not loaded - * @exception IllegalArgumentException if mimeType is - * invalid - * @exception NullPointerException if mimeType is null - */ - public DataFlavor(String mimeType, String humanPresentableName, ClassLoader classLoader) throws ClassNotFoundException { - super(); - if (mimeType == null) { - throw new NullPointerException("mimeType"); - } - try { - initialize(mimeType, humanPresentableName, classLoader); - } catch (MimeTypeParseException mtpe) { - throw new IllegalArgumentException("failed to parse:" + mimeType); - } - } - - /** - * Constructs a DataFlavor from a mimeType string. - * The string can specify a "class=<fully specified Java class name>" - * parameter to create a DataFlavor with the desired - * representation class. If the string does not contain "class=" parameter, - * java.io.InputStream is used as default. - * - * @param mimeType the string used to identify the MIME type for this flavor; - * if the class specified by "class=" parameter is not - * successfully loaded, then an - * ClassNotFoundException is thrown - * @exception ClassNotFoundException if the class is not loaded - * @exception IllegalArgumentException if mimeType is - * invalid - * @exception NullPointerException if mimeType is null - */ - public DataFlavor(String mimeType) throws ClassNotFoundException { - super(); - if (mimeType == null) { - throw new NullPointerException("mimeType"); - } - try { - initialize(mimeType, null, this.getClass().getClassLoader()); - } catch (MimeTypeParseException mtpe) { - throw new IllegalArgumentException("failed to parse:" + mimeType); - } - } - - /** - * Common initialization code called from various constructors. - * - * @param mimeType the MIME Content Type (must have a class= param) - * @param humanPresentableName the human Presentable Name or - * null - * @param classLoader the fallback class loader to resolve against - * - * @throws MimeTypeParseException - * @throws ClassNotFoundException - * @throws NullPointerException if mimeType is null - * - * @see #tryToLoadClass - */ - private void initialize(String mimeType, String humanPresentableName, ClassLoader classLoader) throws MimeTypeParseException, ClassNotFoundException { - if (mimeType == null) { - throw new NullPointerException("mimeType"); - } - - this.mimeType = new MimeType(mimeType); // throws - - String rcn = getParameter("class"); - - if (rcn == null) { - if ("application/x-java-serialized-object".equals(this.mimeType.getBaseType())) - - throw new IllegalArgumentException("no representation class specified for:" + mimeType); - else - representationClass = java.io.InputStream.class; // default - } else { // got a class name - representationClass = DataFlavor.tryToLoadClass(rcn, classLoader); - } - - this.mimeType.setParameter("class", representationClass.getName()); - - if (humanPresentableName == null) { - humanPresentableName = this.mimeType.getParameter("humanPresentableName"); - if (humanPresentableName == null) - humanPresentableName = this.mimeType.getPrimaryType() + "/" + this.mimeType.getSubType(); - } - - this.humanPresentableName = humanPresentableName; // set it. - - this.mimeType.removeParameter("humanPresentableName"); // just in case - } - - /** - * String representation of this DataFlavor and its - * parameters. The resulting String contains the name of - * the DataFlavor class, this flavor's MIME type, and its - * representation class. If this flavor has a primary MIME type of "text", - * supports the charset parameter, and has an encoded representation, the - * flavor's charset is also included. See selectBestTextFlavor - * for a list of text flavors which support the charset parameter. - * - * @return string representation of this DataFlavor - * @see #selectBestTextFlavor - */ - public String toString() { - String string = getClass().getName(); - string += "["+paramString()+"]"; - return string; - } - - private String paramString() { - String params = ""; - params += "mimetype="; - if (mimeType == null) { - params += "null"; - } else { - params += mimeType.getBaseType(); - } - params += ";representationclass="; - if (representationClass == null) { - params += "null"; - } else { - params += representationClass.getName(); - } - if (DataFlavorUtil.isFlavorCharsetTextType(this) && - (isRepresentationClassInputStream() || - isRepresentationClassByteBuffer() || - byte[].class.equals(representationClass))) - { - params += ";charset=" + DataFlavorUtil.getTextCharset(this); - } - return params; - } - - /** - * Returns a DataFlavor representing plain text with Unicode - * encoding, where: - *
-     *     representationClass = java.io.InputStream
-     *     mimeType            = "text/plain;
-     *                            charset=<platform default Unicode encoding>"
-     * 
- * Sun's implementation for Microsoft Windows uses the encoding utf-16le. - * Sun's implementation for Solaris and Linux uses the encoding - * iso-10646-ucs-2. - * - * @return a DataFlavor representing plain text - * with Unicode encoding - * @since 1.3 - */ - public static final DataFlavor getTextPlainUnicodeFlavor() { - return new DataFlavor( - "text/plain;charset=" + DataFlavorUtil.getDesktopService().getDefaultUnicodeEncoding() - +";class=java.io.InputStream", "Plain Text"); - } - - /** - * Selects the best text DataFlavor from an array of - * DataFlavors. Only DataFlavor.stringFlavor, and - * equivalent flavors, and flavors that have a primary MIME type of "text", - * are considered for selection. - *

- * Flavors are first sorted by their MIME types in the following order: - *

    - *
  • "text/sgml" - *
  • "text/xml" - *
  • "text/html" - *
  • "text/rtf" - *
  • "text/enriched" - *
  • "text/richtext" - *
  • "text/uri-list" - *
  • "text/tab-separated-values" - *
  • "text/t140" - *
  • "text/rfc822-headers" - *
  • "text/parityfec" - *
  • "text/directory" - *
  • "text/css" - *
  • "text/calendar" - *
  • "application/x-java-serialized-object" - *
  • "text/plain" - *
  • "text/<other>" - *
- *

For example, "text/sgml" will be selected over - * "text/html", and DataFlavor.stringFlavor will be chosen - * over DataFlavor.plainTextFlavor. - *

- * If two or more flavors share the best MIME type in the array, then that - * MIME type will be checked to see if it supports the charset parameter. - *

- * The following MIME types support, or are treated as though they support, - * the charset parameter: - *

    - *
  • "text/sgml" - *
  • "text/xml" - *
  • "text/html" - *
  • "text/enriched" - *
  • "text/richtext" - *
  • "text/uri-list" - *
  • "text/directory" - *
  • "text/css" - *
  • "text/calendar" - *
  • "application/x-java-serialized-object" - *
  • "text/plain" - *
- * The following MIME types do not support, or are treated as though they - * do not support, the charset parameter: - *
    - *
  • "text/rtf" - *
  • "text/tab-separated-values" - *
  • "text/t140" - *
  • "text/rfc822-headers" - *
  • "text/parityfec" - *
- * For "text/<other>" MIME types, the first time the JRE needs to - * determine whether the MIME type supports the charset parameter, it will - * check whether the parameter is explicitly listed in an arbitrarily - * chosen DataFlavor which uses that MIME type. If so, the JRE - * will assume from that point on that the MIME type supports the charset - * parameter and will not check again. If the parameter is not explicitly - * listed, the JRE will assume from that point on that the MIME type does - * not support the charset parameter and will not check again. Because - * this check is performed on an arbitrarily chosen - * DataFlavor, developers must ensure that all - * DataFlavors with a "text/<other>" MIME type specify - * the charset parameter if it is supported by that MIME type. Developers - * should never rely on the JRE to substitute the platform's default - * charset for a "text/<other>" DataFlavor. Failure to adhere to this - * restriction will lead to undefined behavior. - *

- * If the best MIME type in the array does not support the charset - * parameter, the flavors which share that MIME type will then be sorted by - * their representation classes in the following order: - * java.io.InputStream, java.nio.ByteBuffer, - * [B, <all others>. - *

- * If two or more flavors share the best representation class, or if no - * flavor has one of the three specified representations, then one of those - * flavors will be chosen non-deterministically. - *

- * If the best MIME type in the array does support the charset parameter, - * the flavors which share that MIME type will then be sorted by their - * representation classes in the following order: - * java.io.Reader, java.lang.String, - * java.nio.CharBuffer, [C, <all others>. - *

- * If two or more flavors share the best representation class, and that - * representation is one of the four explicitly listed, then one of those - * flavors will be chosen non-deterministically. If, however, no flavor has - * one of the four specified representations, the flavors will then be - * sorted by their charsets. Unicode charsets, such as "UTF-16", "UTF-8", - * "UTF-16BE", "UTF-16LE", and their aliases, are considered best. After - * them, the platform default charset and its aliases are selected. - * "US-ASCII" and its aliases are worst. All other charsets are chosen in - * alphabetical order, but only charsets supported by this implementation - * of the Java platform will be considered. - *

- * If two or more flavors share the best charset, the flavors will then - * again be sorted by their representation classes in the following order: - * java.io.InputStream, java.nio.ByteBuffer, - * [B, <all others>. - *

- * If two or more flavors share the best representation class, or if no - * flavor has one of the three specified representations, then one of those - * flavors will be chosen non-deterministically. - * - * @param availableFlavors an array of available DataFlavors - * @return the best (highest fidelity) flavor according to the rules - * specified above, or null, - * if availableFlavors is null, - * has zero length, or contains no text flavors - * @since 1.3 - */ - public static final DataFlavor selectBestTextFlavor( - DataFlavor[] availableFlavors) { - if (availableFlavors == null || availableFlavors.length == 0) { - return null; - } - - DataFlavor bestFlavor = Collections.max(Arrays.asList(availableFlavors), - DataFlavorUtil.getTextFlavorComparator()); - - if (!bestFlavor.isFlavorTextType()) { - return null; - } - - return bestFlavor; - } - - /** - * Gets a Reader for a text flavor, decoded, if necessary, for the expected - * charset (encoding). The supported representation classes are - * java.io.Reader, java.lang.String, - * java.nio.CharBuffer, [C, - * java.io.InputStream, java.nio.ByteBuffer, - * and [B. - *

- * Because text flavors which do not support the charset parameter are - * encoded in a non-standard format, this method should not be called for - * such flavors. However, in order to maintain backward-compatibility, - * if this method is called for such a flavor, this method will treat the - * flavor as though it supports the charset parameter and attempt to - * decode it accordingly. See selectBestTextFlavor for a list - * of text flavors which do not support the charset parameter. - * - * @param transferable the Transferable whose data will be - * requested in this flavor - * - * @return a Reader to read the Transferable's - * data - * - * @exception IllegalArgumentException if the representation class - * is not one of the seven listed above - * @exception IllegalArgumentException if the Transferable - * has null data - * @exception NullPointerException if the Transferable is - * null - * @exception UnsupportedEncodingException if this flavor's representation - * is java.io.InputStream, - * java.nio.ByteBuffer, or [B and - * this flavor's encoding is not supported by this - * implementation of the Java platform - * @exception UnsupportedFlavorException if the Transferable - * does not support this flavor - * @exception IOException if the data cannot be read because of an - * I/O error - * @see #selectBestTextFlavor - * @since 1.3 - */ - public Reader getReaderForText(Transferable transferable) - throws UnsupportedFlavorException, IOException - { - Object transferObject = transferable.getTransferData(this); - if (transferObject == null) { - throw new IllegalArgumentException - ("getTransferData() returned null"); - } - - if (transferObject instanceof Reader) { - return (Reader)transferObject; - } else if (transferObject instanceof String) { - return new StringReader((String)transferObject); - } else if (transferObject instanceof CharBuffer) { - CharBuffer buffer = (CharBuffer)transferObject; - int size = buffer.remaining(); - char[] chars = new char[size]; - buffer.get(chars, 0, size); - return new CharArrayReader(chars); - } else if (transferObject instanceof char[]) { - return new CharArrayReader((char[])transferObject); - } - - InputStream stream = null; - - if (transferObject instanceof InputStream) { - stream = (InputStream)transferObject; - } else if (transferObject instanceof ByteBuffer) { - ByteBuffer buffer = (ByteBuffer)transferObject; - int size = buffer.remaining(); - byte[] bytes = new byte[size]; - buffer.get(bytes, 0, size); - stream = new ByteArrayInputStream(bytes); - } else if (transferObject instanceof byte[]) { - stream = new ByteArrayInputStream((byte[])transferObject); - } - - if (stream == null) { - throw new IllegalArgumentException("transfer data is not Reader, String, CharBuffer, char array, InputStream, ByteBuffer, or byte array"); - } - - String encoding = getParameter("charset"); - return (encoding == null) - ? new InputStreamReader(stream) - : new InputStreamReader(stream, encoding); - } - - /** - * Returns the MIME type string for this DataFlavor. - * @return the MIME type string for this flavor - */ - public String getMimeType() { - return (mimeType != null) ? mimeType.toString() : null; - } - - /** - * Returns the Class which objects supporting this - * DataFlavor will return when this DataFlavor - * is requested. - * @return the Class which objects supporting this - * DataFlavor will return when this DataFlavor - * is requested - */ - public Class getRepresentationClass() { - return representationClass; - } - - /** - * Returns the human presentable name for the data format that this - * DataFlavor represents. This name would be localized - * for different countries. - * @return the human presentable name for the data format that this - * DataFlavor represents - */ - public String getHumanPresentableName() { - return humanPresentableName; - } - - /** - * Returns the primary MIME type for this DataFlavor. - * @return the primary MIME type of this DataFlavor - */ - public String getPrimaryType() { - return (mimeType != null) ? mimeType.getPrimaryType() : null; - } - - /** - * Returns the sub MIME type of this DataFlavor. - * @return the Sub MIME type of this DataFlavor - */ - public String getSubType() { - return (mimeType != null) ? mimeType.getSubType() : null; - } - - /** - * Returns the human presentable name for this DataFlavor - * if paramName equals "humanPresentableName". Otherwise - * returns the MIME type value associated with paramName. - * - * @param paramName the parameter name requested - * @return the value of the name parameter, or null - * if there is no associated value - */ - public String getParameter(String paramName) { - if (paramName.equals("humanPresentableName")) { - return humanPresentableName; - } else { - return (mimeType != null) - ? mimeType.getParameter(paramName) : null; - } - } - - /** - * Sets the human presentable name for the data format that this - * DataFlavor represents. This name would be localized - * for different countries. - * @param humanPresentableName the new human presentable name - */ - public void setHumanPresentableName(String humanPresentableName) { - this.humanPresentableName = humanPresentableName; - } - - /** - * {@inheritDoc} - *

- * The equals comparison for the {@code DataFlavor} class is implemented - * as follows: Two DataFlavors are considered equal if and - * only if their MIME primary type and subtype and representation class are - * equal. Additionally, if the primary type is "text", the subtype denotes - * a text flavor which supports the charset parameter, and the - * representation class is not java.io.Reader, - * java.lang.String, java.nio.CharBuffer, or - * [C, the charset parameter must also be equal. - * If a charset is not explicitly specified for one or both - * DataFlavors, the platform default encoding is assumed. See - * selectBestTextFlavor for a list of text flavors which - * support the charset parameter. - * - * @param o the Object to compare with this - * @return true if that is equivalent to this - * DataFlavor; false otherwise - * @see #selectBestTextFlavor - */ - public boolean equals(Object o) { - return ((o instanceof DataFlavor) && equals((DataFlavor)o)); - } - - /** - * This method has the same behavior as {@link #equals(Object)}. - * The only difference being that it takes a {@code DataFlavor} instance - * as a parameter. - * - * @param that the DataFlavor to compare with - * this - * @return true if that is equivalent to this - * DataFlavor; false otherwise - * @see #selectBestTextFlavor - */ - public boolean equals(DataFlavor that) { - if (that == null) { - return false; - } - if (this == that) { - return true; - } - - if (!Objects.equals(this.getRepresentationClass(), that.getRepresentationClass())) { - return false; - } - - if (mimeType == null) { - if (that.mimeType != null) { - return false; - } - } else { - if (!mimeType.match(that.mimeType)) { - return false; - } - - if ("text".equals(getPrimaryType())) { - if (DataFlavorUtil.doesSubtypeSupportCharset(this) - && representationClass != null - && !isStandardTextRepresentationClass()) { - String thisCharset = - DataFlavorUtil.canonicalName(this.getParameter("charset")); - String thatCharset = - DataFlavorUtil.canonicalName(that.getParameter("charset")); - if (!Objects.equals(thisCharset, thatCharset)) { - return false; - } - } - - if ("html".equals(getSubType())) { - String thisDocument = this.getParameter("document"); - String thatDocument = that.getParameter("document"); - if (!Objects.equals(thisDocument, thatDocument)) { - return false; - } - } - } - } - - return true; - } - - /** - * Compares only the mimeType against the passed in - * String and representationClass is - * not considered in the comparison. - * - * If representationClass needs to be compared, then - * equals(new DataFlavor(s)) may be used. - * @deprecated As inconsistent with hashCode() contract, - * use isMimeTypeEqual(String) instead. - * @param s the {@code mimeType} to compare. - * @return true if the String (MimeType) is equal; false otherwise or if - * {@code s} is {@code null} - */ - @Deprecated - public boolean equals(String s) { - if (s == null || mimeType == null) - return false; - return isMimeTypeEqual(s); - } - - /** - * Returns hash code for this DataFlavor. - * For two equal DataFlavors, hash codes are equal. - * For the String - * that matches DataFlavor.equals(String), it is not - * guaranteed that DataFlavor's hash code is equal - * to the hash code of the String. - * - * @return a hash code for this DataFlavor - */ - public int hashCode() { - int total = 0; - - if (representationClass != null) { - total += representationClass.hashCode(); - } - - if (mimeType != null) { - String primaryType = mimeType.getPrimaryType(); - if (primaryType != null) { - total += primaryType.hashCode(); - } - - // Do not add subType.hashCode() to the total. equals uses - // MimeType.match which reports a match if one or both of the - // subTypes is '*', regardless of the other subType. - - if ("text".equals(primaryType)) { - if (DataFlavorUtil.doesSubtypeSupportCharset(this) - && representationClass != null - && !isStandardTextRepresentationClass()) { - String charset = DataFlavorUtil.canonicalName(getParameter("charset")); - if (charset != null) { - total += charset.hashCode(); - } - } - - if ("html".equals(getSubType())) { - String document = this.getParameter("document"); - if (document != null) { - total += document.hashCode(); - } - } - } - } - - return total; - } - - /** - * Identical to {@link #equals(DataFlavor)}. - * - * @param that the DataFlavor to compare with - * this - * @return true if that is equivalent to this - * DataFlavor; false otherwise - * @see #selectBestTextFlavor - * @since 1.3 - */ - public boolean match(DataFlavor that) { - return equals(that); - } - - /** - * Returns whether the string representation of the MIME type passed in - * is equivalent to the MIME type of this DataFlavor. - * Parameters are not included in the comparison. - * - * @param mimeType the string representation of the MIME type - * @return true if the string representation of the MIME type passed in is - * equivalent to the MIME type of this DataFlavor; - * false otherwise - * @throws NullPointerException if mimeType is null - */ - public boolean isMimeTypeEqual(String mimeType) { - // JCK Test DataFlavor0117: if 'mimeType' is null, throw NPE - if (mimeType == null) { - throw new NullPointerException("mimeType"); - } - if (this.mimeType == null) { - return false; - } - try { - return this.mimeType.match(new MimeType(mimeType)); - } catch (MimeTypeParseException mtpe) { - return false; - } - } - - /** - * Compares the mimeType of two DataFlavor - * objects. No parameters are considered. - * - * @param dataFlavor the DataFlavor to be compared - * @return true if the MimeTypes are equal, - * otherwise false - */ - - public final boolean isMimeTypeEqual(DataFlavor dataFlavor) { - return isMimeTypeEqual(dataFlavor.mimeType); - } - - /** - * Compares the mimeType of two DataFlavor - * objects. No parameters are considered. - * - * @return true if the MimeTypes are equal, - * otherwise false - */ - - private boolean isMimeTypeEqual(MimeType mtype) { - if (this.mimeType == null) { - return (mtype == null); - } - return mimeType.match(mtype); - } - - /** - * Checks if the representation class is one of the standard text - * representation classes. - * - * @return true if the representation class is one of the standard text - * representation classes, otherwise false - */ - private boolean isStandardTextRepresentationClass() { - return isRepresentationClassReader() - || String.class.equals(representationClass) - || isRepresentationClassCharBuffer() - || char[].class.equals(representationClass); - } - - /** - * Does the DataFlavor represent a serialized object? - * @return whether or not a serialized object is represented - */ - public boolean isMimeTypeSerializedObject() { - return isMimeTypeEqual(javaSerializedObjectMimeType); - } - - /** - * Returns the default representation class. - * @return the default representation class - */ - public final Class getDefaultRepresentationClass() { - return ioInputStreamClass; - } - - /** - * Returns the name of the default representation class. - * @return the name of the default representation class - */ - public final String getDefaultRepresentationClassAsString() { - return getDefaultRepresentationClass().getName(); - } - - /** - * Does the DataFlavor represent a - * java.io.InputStream? - * @return whether or not this {@code DataFlavor} represent a - * {@code java.io.InputStream} - */ - public boolean isRepresentationClassInputStream() { - return ioInputStreamClass.isAssignableFrom(representationClass); - } - - /** - * Returns whether the representation class for this - * DataFlavor is java.io.Reader or a subclass - * thereof. - * @return whether or not the representation class for this - * {@code DataFlavor} is {@code java.io.Reader} or a subclass - * thereof - * - * @since 1.4 - */ - public boolean isRepresentationClassReader() { - return java.io.Reader.class.isAssignableFrom(representationClass); - } - - /** - * Returns whether the representation class for this - * DataFlavor is java.nio.CharBuffer or a - * subclass thereof. - * @return whether or not the representation class for this - * {@code DataFlavor} is {@code java.nio.CharBuffer} or a subclass - * thereof - * - * @since 1.4 - */ - public boolean isRepresentationClassCharBuffer() { - return java.nio.CharBuffer.class.isAssignableFrom(representationClass); - } - - /** - * Returns whether the representation class for this - * DataFlavor is java.nio.ByteBuffer or a - * subclass thereof. - * @return whether or not the representation class for this - * {@code DataFlavor} is {@code java.nio.ByteBuffer} or a subclass - * thereof - * - * @since 1.4 - */ - public boolean isRepresentationClassByteBuffer() { - return java.nio.ByteBuffer.class.isAssignableFrom(representationClass); - } - - /** - * Returns true if the representation class can be serialized. - * @return true if the representation class can be serialized - */ - - public boolean isRepresentationClassSerializable() { - return java.io.Serializable.class.isAssignableFrom(representationClass); - } - - /** - * Returns true if the representation class is Remote. - * @return true if the representation class is Remote - */ - public boolean isRepresentationClassRemote() { - return DataFlavorUtil.RMI.isRemote(representationClass); - } - - /** - * Returns true if the DataFlavor specified represents - * a serialized object. - * @return true if the DataFlavor specified represents - * a Serialized Object - */ - - public boolean isFlavorSerializedObjectType() { - return isRepresentationClassSerializable() && isMimeTypeEqual(javaSerializedObjectMimeType); - } - - /** - * Returns true if the DataFlavor specified represents - * a remote object. - * @return true if the DataFlavor specified represents - * a Remote Object - */ - - public boolean isFlavorRemoteObjectType() { - return isRepresentationClassRemote() - && isRepresentationClassSerializable() - && isMimeTypeEqual(javaRemoteObjectMimeType); - } - - - /** - * Returns true if the DataFlavor specified represents - * a list of file objects. - * @return true if the DataFlavor specified represents - * a List of File objects - */ - - public boolean isFlavorJavaFileListType() { - if (mimeType == null || representationClass == null) - return false; - return java.util.List.class.isAssignableFrom(representationClass) && - mimeType.match(javaFileListFlavor.mimeType); - - } - - /** - * Returns whether this DataFlavor is a valid text flavor for - * this implementation of the Java platform. Only flavors equivalent to - * DataFlavor.stringFlavor and DataFlavors with - * a primary MIME type of "text" can be valid text flavors. - *

- * If this flavor supports the charset parameter, it must be equivalent to - * DataFlavor.stringFlavor, or its representation must be - * java.io.Reader, java.lang.String, - * java.nio.CharBuffer, [C, - * java.io.InputStream, java.nio.ByteBuffer, or - * [B. If the representation is - * java.io.InputStream, java.nio.ByteBuffer, or - * [B, then this flavor's charset parameter must - * be supported by this implementation of the Java platform. If a charset - * is not specified, then the platform default charset, which is always - * supported, is assumed. - *

- * If this flavor does not support the charset parameter, its - * representation must be java.io.InputStream, - * java.nio.ByteBuffer, or [B. - *

- * See selectBestTextFlavor for a list of text flavors which - * support the charset parameter. - * - * @return true if this DataFlavor is a valid - * text flavor as described above; false otherwise - * @see #selectBestTextFlavor - * @since 1.4 - */ - public boolean isFlavorTextType() { - return (DataFlavorUtil.isFlavorCharsetTextType(this) || - DataFlavorUtil.isFlavorNoncharsetTextType(this)); - } - - /** - * Serializes this DataFlavor. - */ - - public synchronized void writeExternal(ObjectOutput os) throws IOException { - if (mimeType != null) { - mimeType.setParameter("humanPresentableName", humanPresentableName); - os.writeObject(mimeType); - mimeType.removeParameter("humanPresentableName"); - } else { - os.writeObject(null); - } - - os.writeObject(representationClass); - } - - /** - * Restores this DataFlavor from a Serialized state. - */ - - public synchronized void readExternal(ObjectInput is) throws IOException , ClassNotFoundException { - String rcn = null; - mimeType = (MimeType)is.readObject(); - - if (mimeType != null) { - humanPresentableName = - mimeType.getParameter("humanPresentableName"); - mimeType.removeParameter("humanPresentableName"); - rcn = mimeType.getParameter("class"); - if (rcn == null) { - throw new IOException("no class parameter specified in: " + - mimeType); - } - } - - try { - representationClass = (Class)is.readObject(); - } catch (OptionalDataException ode) { - if (!ode.eof || ode.length != 0) { - throw ode; - } - // Ensure backward compatibility. - // Old versions didn't write the representation class to the stream. - if (rcn != null) { - representationClass = - DataFlavor.tryToLoadClass(rcn, getClass().getClassLoader()); - } - } - } - - /** - * Returns a clone of this DataFlavor. - * @return a clone of this DataFlavor - */ - - public Object clone() throws CloneNotSupportedException { - Object newObj = super.clone(); - if (mimeType != null) { - ((DataFlavor)newObj).mimeType = (MimeType)mimeType.clone(); - } - return newObj; - } // clone() - - /** - * Called on DataFlavor for every MIME Type parameter - * to allow DataFlavor subclasses to handle special - * parameters like the text/plain charset - * parameters, whose values are case insensitive. (MIME type parameter - * values are supposed to be case sensitive. - *

- * This method is called for each parameter name/value pair and should - * return the normalized representation of the parameterValue. - * - * This method is never invoked by this implementation from 1.1 onwards. - * - * @param parameterName the parameter name - * @param parameterValue the parameter value - * @return the parameter value - * @deprecated - */ - @Deprecated - protected String normalizeMimeTypeParameter(String parameterName, String parameterValue) { - return parameterValue; - } - - /** - * Called for each MIME type string to give DataFlavor subtypes - * the opportunity to change how the normalization of MIME types is - * accomplished. One possible use would be to add default - * parameter/value pairs in cases where none are present in the MIME - * type string passed in. - * - * This method is never invoked by this implementation from 1.1 onwards. - * - * @param mimeType the mime type - * @return the mime type - * @deprecated - */ - @Deprecated - protected String normalizeMimeType(String mimeType) { - return mimeType; - } - - /* - * fields - */ - - /* placeholder for caching any platform-specific data for flavor */ - - transient int atom; - - /* Mime Type of DataFlavor */ - - MimeType mimeType; - - private String humanPresentableName; - - /** Java class of objects this DataFlavor represents **/ - - private Class representationClass; - -} // class DataFlavor --- /dev/null 2015-01-13 17:32:21.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java 2015-01-13 17:32:08.395262400 +0400 @@ -0,0 +1,1433 @@ +/* + * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.awt.datatransfer; + +import sun.datatransfer.DataFlavorUtil; +import sun.reflect.misc.ReflectUtil; + +import java.io.ByteArrayInputStream; +import java.io.CharArrayReader; +import java.io.Externalizable; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.OptionalDataException; +import java.io.Reader; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.util.Arrays; +import java.util.Collections; +import java.util.Objects; + +import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; + +/** + * A {@code DataFlavor} provides meta information about data. {@code DataFlavor} + * is typically used to access data on the clipboard, or during + * a drag and drop operation. + *

+ * An instance of {@code DataFlavor} encapsulates a content type as + * defined in RFC 2045 + * and RFC 2046. + * A content type is typically referred to as a MIME type. + *

+ * A content type consists of a media type (referred + * to as the primary type), a subtype, and optional parameters. See + * RFC 2045 + * for details on the syntax of a MIME type. + *

+ * The JRE data transfer implementation interprets the parameter "class" + * of a MIME type as a representation class. + * The representation class reflects the class of the object being + * transferred. In other words, the representation class is the type of + * object returned by {@link Transferable#getTransferData}. + * For example, the MIME type of {@link #imageFlavor} is + * {@code "image/x-java-image;class=java.awt.Image"}, + * the primary type is {@code image}, the subtype is + * {@code x-java-image}, and the representation class is + * {@code java.awt.Image}. When {@code getTransferData} is invoked + * with a {@code DataFlavor} of {@code imageFlavor}, an instance of + * {@code java.awt.Image} is returned. + * It's important to note that {@code DataFlavor} does no error checking + * against the representation class. It is up to consumers of + * {@code DataFlavor}, such as {@code Transferable}, to honor the representation + * class. + *
+ * Note, if you do not specify a representation class when + * creating a {@code DataFlavor}, the default + * representation class is used. See appropriate documentation for + * {@code DataFlavor}'s constructors. + *

+ * Also, {@code DataFlavor} instances with the "text" primary + * MIME type may have a "charset" parameter. Refer to + * RFC 2046 and + * {@link #selectBestTextFlavor} for details on "text" MIME types + * and the "charset" parameter. + *

+ * Equality of {@code DataFlavors} is determined by the primary type, + * subtype, and representation class. Refer to {@link #equals(DataFlavor)} for + * details. When determining equality, any optional parameters are ignored. + * For example, the following produces two {@code DataFlavors} that + * are considered identical: + *

+ *   DataFlavor flavor1 = new DataFlavor(Object.class, "X-test/test; class=<java.lang.Object>; foo=bar");
+ *   DataFlavor flavor2 = new DataFlavor(Object.class, "X-test/test; class=<java.lang.Object>; x=y");
+ *   // The following returns true.
+ *   flavor1.equals(flavor2);
+ * 
+ * As mentioned, {@code flavor1} and {@code flavor2} are considered identical. + * As such, asking a {@code Transferable} for either {@code DataFlavor} returns + * the same results. + *

+ * For more information on using data transfer with Swing see + * the + * How to Use Drag and Drop and Data Transfer, + * section in Java Tutorial. + * + * @author Blake Sullivan + * @author Laurence P. G. Cable + * @author Jeff Dunn + */ +public class DataFlavor implements Externalizable, Cloneable { + + private static final long serialVersionUID = 8367026044764648243L; + private static final Class ioInputStreamClass = InputStream.class; + + /** + * Tries to load a class from: the bootstrap loader, the system loader, + * the context loader (if one is present) and finally the loader specified. + * + * @param className the name of the class to be loaded + * @param fallback the fallback loader + * @return the class loaded + * @exception ClassNotFoundException if class is not found + */ + protected final static Class tryToLoadClass(String className, + ClassLoader fallback) + throws ClassNotFoundException + { + ReflectUtil.checkPackageAccess(className); + try { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(GET_CLASSLOADER_PERMISSION); + } + ClassLoader loader = ClassLoader.getSystemClassLoader(); + try { + // bootstrap class loader and system class loader if present + return Class.forName(className, true, loader); + } + catch (ClassNotFoundException exception) { + // thread context class loader if and only if present + loader = Thread.currentThread().getContextClassLoader(); + if (loader != null) { + try { + return Class.forName(className, true, loader); + } + catch (ClassNotFoundException e) { + // fallback to user's class loader + } + } + } + } catch (SecurityException exception) { + // ignore secured class loaders + } + return Class.forName(className, true, fallback); + } + + /* + * private initializer + */ + static private DataFlavor createConstant(Class rc, String prn) { + try { + return new DataFlavor(rc, prn); + } catch (Exception e) { + return null; + } + } + + /* + * private initializer + */ + static private DataFlavor createConstant(String mt, String prn) { + try { + return new DataFlavor(mt, prn); + } catch (Exception e) { + return null; + } + } + + /* + * private initializer + */ + static private DataFlavor initHtmlDataFlavor(String htmlFlavorType) { + try { + return new DataFlavor ("text/html; class=java.lang.String;document=" + + htmlFlavorType + ";charset=Unicode"); + } catch (Exception e) { + return null; + } + } + + /** + * The DataFlavor representing a Java Unicode String class, + * where: + *

+     *     representationClass = java.lang.String
+     *     mimeType           = "application/x-java-serialized-object"
+     * 
+ */ + public static final DataFlavor stringFlavor = createConstant(java.lang.String.class, "Unicode String"); + + /** + * The DataFlavor representing a Java Image class, + * where: + *
+     *     representationClass = java.awt.Image
+     *     mimeType            = "image/x-java-image"
+     * 
+ */ + public static final DataFlavor imageFlavor = createConstant("image/x-java-image; class=java.awt.Image", "Image"); + + /** + * The DataFlavor representing plain text with Unicode + * encoding, where: + *
+     *     representationClass = InputStream
+     *     mimeType            = "text/plain; charset=unicode"
+     * 
+ * This DataFlavor has been deprecated because + * (1) Its representation is an InputStream, an 8-bit based representation, + * while Unicode is a 16-bit character set; and (2) The charset "unicode" + * is not well-defined. "unicode" implies a particular platform's + * implementation of Unicode, not a cross-platform implementation. + * + * @deprecated as of 1.3. Use DataFlavor.getReaderForText(Transferable) + * instead of Transferable.getTransferData(DataFlavor.plainTextFlavor). + */ + @Deprecated + public static final DataFlavor plainTextFlavor = createConstant("text/plain; charset=unicode; class=java.io.InputStream", "Plain Text"); + + /** + * A MIME Content-Type of application/x-java-serialized-object represents + * a graph of Java object(s) that have been made persistent. + * + * The representation class associated with this DataFlavor + * identifies the Java type of an object returned as a reference + * from an invocation java.awt.datatransfer.getTransferData. + */ + public static final String javaSerializedObjectMimeType = "application/x-java-serialized-object"; + + /** + * To transfer a list of files to/from Java (and the underlying + * platform) a DataFlavor of this type/subtype and + * representation class of java.util.List is used. + * Each element of the list is required/guaranteed to be of type + * java.io.File. + */ + public static final DataFlavor javaFileListFlavor = createConstant("application/x-java-file-list;class=java.util.List", null); + + /** + * To transfer a reference to an arbitrary Java object reference that + * has no associated MIME Content-type, across a Transferable + * interface WITHIN THE SAME JVM, a DataFlavor + * with this type/subtype is used, with a representationClass + * equal to the type of the class/interface being passed across the + * Transferable. + *

+ * The object reference returned from + * Transferable.getTransferData for a DataFlavor + * with this MIME Content-Type is required to be + * an instance of the representation Class of the DataFlavor. + */ + public static final String javaJVMLocalObjectMimeType = "application/x-java-jvm-local-objectref"; + + /** + * In order to pass a live link to a Remote object via a Drag and Drop + * ACTION_LINK operation a Mime Content Type of + * application/x-java-remote-object should be used, + * where the representation class of the DataFlavor + * represents the type of the Remote interface to be + * transferred. + */ + public static final String javaRemoteObjectMimeType = "application/x-java-remote-object"; + + /** + * Represents a piece of an HTML markup. The markup consists of the part + * selected on the source side. Therefore some tags in the markup may be + * unpaired. If the flavor is used to represent the data in + * a {@link Transferable} instance, no additional changes will be made. + * This DataFlavor instance represents the same HTML markup as DataFlavor + * instances which content MIME type does not contain document parameter + * and representation class is the String class. + *

+     *     representationClass = String
+     *     mimeType           = "text/html"
+     * 
+ */ + public static DataFlavor selectionHtmlFlavor = initHtmlDataFlavor("selection"); + + /** + * Represents a piece of an HTML markup. If possible, the markup received + * from a native system is supplemented with pair tags to be + * a well-formed HTML markup. If the flavor is used to represent the data in + * a {@link Transferable} instance, no additional changes will be made. + *
+     *     representationClass = String
+     *     mimeType           = "text/html"
+     * 
+ */ + public static DataFlavor fragmentHtmlFlavor = initHtmlDataFlavor("fragment"); + + /** + * Represents a piece of an HTML markup. If possible, the markup + * received from a native system is supplemented with additional + * tags to make up a well-formed HTML document. If the flavor is used to + * represent the data in a {@link Transferable} instance, + * no additional changes will be made. + *
+     *     representationClass = String
+     *     mimeType           = "text/html"
+     * 
+ */ + public static DataFlavor allHtmlFlavor = initHtmlDataFlavor("all"); + + /** + * Constructs a new DataFlavor. This constructor is + * provided only for the purpose of supporting the + * Externalizable interface. It is not + * intended for public (client) use. + * + * @since 1.2 + */ + public DataFlavor() { + super(); + } + + /** + * Constructs a fully specified DataFlavor. + * + * @exception NullPointerException if either primaryType, + * subType or representationClass is null + */ + private DataFlavor(String primaryType, String subType, MimeTypeParameterList params, Class representationClass, String humanPresentableName) { + super(); + if (primaryType == null) { + throw new NullPointerException("primaryType"); + } + if (subType == null) { + throw new NullPointerException("subType"); + } + if (representationClass == null) { + throw new NullPointerException("representationClass"); + } + + if (params == null) params = new MimeTypeParameterList(); + + params.set("class", representationClass.getName()); + + if (humanPresentableName == null) { + humanPresentableName = params.get("humanPresentableName"); + + if (humanPresentableName == null) + humanPresentableName = primaryType + "/" + subType; + } + + try { + mimeType = new MimeType(primaryType, subType, params); + } catch (MimeTypeParseException mtpe) { + throw new IllegalArgumentException("MimeType Parse Exception: " + mtpe.getMessage()); + } + + this.representationClass = representationClass; + this.humanPresentableName = humanPresentableName; + + mimeType.removeParameter("humanPresentableName"); + } + + /** + * Constructs a DataFlavor that represents a Java class. + *

+ * The returned DataFlavor will have the following + * characteristics: + *

+     *    representationClass = representationClass
+     *    mimeType            = application/x-java-serialized-object
+     * 
+ * @param representationClass the class used to transfer data in this flavor + * @param humanPresentableName the human-readable string used to identify + * this flavor; if this parameter is null + * then the value of the MIME Content Type is used + * @exception NullPointerException if representationClass is null + */ + public DataFlavor(Class representationClass, String humanPresentableName) { + this("application", "x-java-serialized-object", null, representationClass, humanPresentableName); + if (representationClass == null) { + throw new NullPointerException("representationClass"); + } + } + + /** + * Constructs a DataFlavor that represents a + * MimeType. + *

+ * The returned DataFlavor will have the following + * characteristics: + *

+ * If the mimeType is + * "application/x-java-serialized-object; class=<representation class>", + * the result is the same as calling + * new DataFlavor(Class.forName(<representation class>). + *

+ * Otherwise: + *

+     *     representationClass = InputStream
+     *     mimeType            = mimeType
+     * 
+ * @param mimeType the string used to identify the MIME type for this flavor; + * if the mimeType does not specify a + * "class=" parameter, or if the class is not successfully + * loaded, then an IllegalArgumentException + * is thrown + * @param humanPresentableName the human-readable string used to identify + * this flavor; if this parameter is null + * then the value of the MIME Content Type is used + * @exception IllegalArgumentException if mimeType is + * invalid or if the class is not successfully loaded + * @exception NullPointerException if mimeType is null + */ + public DataFlavor(String mimeType, String humanPresentableName) { + super(); + if (mimeType == null) { + throw new NullPointerException("mimeType"); + } + try { + initialize(mimeType, humanPresentableName, this.getClass().getClassLoader()); + } catch (MimeTypeParseException mtpe) { + throw new IllegalArgumentException("failed to parse:" + mimeType); + } catch (ClassNotFoundException cnfe) { + throw new IllegalArgumentException("can't find specified class: " + cnfe.getMessage()); + } + } + + /** + * Constructs a DataFlavor that represents a + * MimeType. + *

+ * The returned DataFlavor will have the following + * characteristics: + *

+ * If the mimeType is + * "application/x-java-serialized-object; class=<representation class>", + * the result is the same as calling + * new DataFlavor(Class.forName(<representation class>). + *

+ * Otherwise: + *

+     *     representationClass = InputStream
+     *     mimeType            = mimeType
+     * 
+ * @param mimeType the string used to identify the MIME type for this flavor + * @param humanPresentableName the human-readable string used to + * identify this flavor + * @param classLoader the class loader to use + * @exception ClassNotFoundException if the class is not loaded + * @exception IllegalArgumentException if mimeType is + * invalid + * @exception NullPointerException if mimeType is null + */ + public DataFlavor(String mimeType, String humanPresentableName, ClassLoader classLoader) throws ClassNotFoundException { + super(); + if (mimeType == null) { + throw new NullPointerException("mimeType"); + } + try { + initialize(mimeType, humanPresentableName, classLoader); + } catch (MimeTypeParseException mtpe) { + throw new IllegalArgumentException("failed to parse:" + mimeType); + } + } + + /** + * Constructs a DataFlavor from a mimeType string. + * The string can specify a "class=<fully specified Java class name>" + * parameter to create a DataFlavor with the desired + * representation class. If the string does not contain "class=" parameter, + * java.io.InputStream is used as default. + * + * @param mimeType the string used to identify the MIME type for this flavor; + * if the class specified by "class=" parameter is not + * successfully loaded, then an + * ClassNotFoundException is thrown + * @exception ClassNotFoundException if the class is not loaded + * @exception IllegalArgumentException if mimeType is + * invalid + * @exception NullPointerException if mimeType is null + */ + public DataFlavor(String mimeType) throws ClassNotFoundException { + super(); + if (mimeType == null) { + throw new NullPointerException("mimeType"); + } + try { + initialize(mimeType, null, this.getClass().getClassLoader()); + } catch (MimeTypeParseException mtpe) { + throw new IllegalArgumentException("failed to parse:" + mimeType); + } + } + + /** + * Common initialization code called from various constructors. + * + * @param mimeType the MIME Content Type (must have a class= param) + * @param humanPresentableName the human Presentable Name or + * null + * @param classLoader the fallback class loader to resolve against + * + * @throws MimeTypeParseException + * @throws ClassNotFoundException + * @throws NullPointerException if mimeType is null + * + * @see #tryToLoadClass + */ + private void initialize(String mimeType, String humanPresentableName, ClassLoader classLoader) throws MimeTypeParseException, ClassNotFoundException { + if (mimeType == null) { + throw new NullPointerException("mimeType"); + } + + this.mimeType = new MimeType(mimeType); // throws + + String rcn = getParameter("class"); + + if (rcn == null) { + if ("application/x-java-serialized-object".equals(this.mimeType.getBaseType())) + + throw new IllegalArgumentException("no representation class specified for:" + mimeType); + else + representationClass = java.io.InputStream.class; // default + } else { // got a class name + representationClass = DataFlavor.tryToLoadClass(rcn, classLoader); + } + + this.mimeType.setParameter("class", representationClass.getName()); + + if (humanPresentableName == null) { + humanPresentableName = this.mimeType.getParameter("humanPresentableName"); + if (humanPresentableName == null) + humanPresentableName = this.mimeType.getPrimaryType() + "/" + this.mimeType.getSubType(); + } + + this.humanPresentableName = humanPresentableName; // set it. + + this.mimeType.removeParameter("humanPresentableName"); // just in case + } + + /** + * String representation of this DataFlavor and its + * parameters. The resulting String contains the name of + * the DataFlavor class, this flavor's MIME type, and its + * representation class. If this flavor has a primary MIME type of "text", + * supports the charset parameter, and has an encoded representation, the + * flavor's charset is also included. See selectBestTextFlavor + * for a list of text flavors which support the charset parameter. + * + * @return string representation of this DataFlavor + * @see #selectBestTextFlavor + */ + public String toString() { + String string = getClass().getName(); + string += "["+paramString()+"]"; + return string; + } + + private String paramString() { + String params = ""; + params += "mimetype="; + if (mimeType == null) { + params += "null"; + } else { + params += mimeType.getBaseType(); + } + params += ";representationclass="; + if (representationClass == null) { + params += "null"; + } else { + params += representationClass.getName(); + } + if (DataFlavorUtil.isFlavorCharsetTextType(this) && + (isRepresentationClassInputStream() || + isRepresentationClassByteBuffer() || + byte[].class.equals(representationClass))) + { + params += ";charset=" + DataFlavorUtil.getTextCharset(this); + } + return params; + } + + /** + * Returns a DataFlavor representing plain text with Unicode + * encoding, where: + *
+     *     representationClass = java.io.InputStream
+     *     mimeType            = "text/plain;
+     *                            charset=<platform default Unicode encoding>"
+     * 
+ * Sun's implementation for Microsoft Windows uses the encoding utf-16le. + * Sun's implementation for Solaris and Linux uses the encoding + * iso-10646-ucs-2. + * + * @return a DataFlavor representing plain text + * with Unicode encoding + * @since 1.3 + */ + public static final DataFlavor getTextPlainUnicodeFlavor() { + return new DataFlavor( + "text/plain;charset=" + DataFlavorUtil.getDesktopService().getDefaultUnicodeEncoding() + +";class=java.io.InputStream", "Plain Text"); + } + + /** + * Selects the best text DataFlavor from an array of + * DataFlavors. Only DataFlavor.stringFlavor, and + * equivalent flavors, and flavors that have a primary MIME type of "text", + * are considered for selection. + *

+ * Flavors are first sorted by their MIME types in the following order: + *

    + *
  • "text/sgml" + *
  • "text/xml" + *
  • "text/html" + *
  • "text/rtf" + *
  • "text/enriched" + *
  • "text/richtext" + *
  • "text/uri-list" + *
  • "text/tab-separated-values" + *
  • "text/t140" + *
  • "text/rfc822-headers" + *
  • "text/parityfec" + *
  • "text/directory" + *
  • "text/css" + *
  • "text/calendar" + *
  • "application/x-java-serialized-object" + *
  • "text/plain" + *
  • "text/<other>" + *
+ *

For example, "text/sgml" will be selected over + * "text/html", and DataFlavor.stringFlavor will be chosen + * over DataFlavor.plainTextFlavor. + *

+ * If two or more flavors share the best MIME type in the array, then that + * MIME type will be checked to see if it supports the charset parameter. + *

+ * The following MIME types support, or are treated as though they support, + * the charset parameter: + *

    + *
  • "text/sgml" + *
  • "text/xml" + *
  • "text/html" + *
  • "text/enriched" + *
  • "text/richtext" + *
  • "text/uri-list" + *
  • "text/directory" + *
  • "text/css" + *
  • "text/calendar" + *
  • "application/x-java-serialized-object" + *
  • "text/plain" + *
+ * The following MIME types do not support, or are treated as though they + * do not support, the charset parameter: + *
    + *
  • "text/rtf" + *
  • "text/tab-separated-values" + *
  • "text/t140" + *
  • "text/rfc822-headers" + *
  • "text/parityfec" + *
+ * For "text/<other>" MIME types, the first time the JRE needs to + * determine whether the MIME type supports the charset parameter, it will + * check whether the parameter is explicitly listed in an arbitrarily + * chosen DataFlavor which uses that MIME type. If so, the JRE + * will assume from that point on that the MIME type supports the charset + * parameter and will not check again. If the parameter is not explicitly + * listed, the JRE will assume from that point on that the MIME type does + * not support the charset parameter and will not check again. Because + * this check is performed on an arbitrarily chosen + * DataFlavor, developers must ensure that all + * DataFlavors with a "text/<other>" MIME type specify + * the charset parameter if it is supported by that MIME type. Developers + * should never rely on the JRE to substitute the platform's default + * charset for a "text/<other>" DataFlavor. Failure to adhere to this + * restriction will lead to undefined behavior. + *

+ * If the best MIME type in the array does not support the charset + * parameter, the flavors which share that MIME type will then be sorted by + * their representation classes in the following order: + * java.io.InputStream, java.nio.ByteBuffer, + * [B, <all others>. + *

+ * If two or more flavors share the best representation class, or if no + * flavor has one of the three specified representations, then one of those + * flavors will be chosen non-deterministically. + *

+ * If the best MIME type in the array does support the charset parameter, + * the flavors which share that MIME type will then be sorted by their + * representation classes in the following order: + * java.io.Reader, java.lang.String, + * java.nio.CharBuffer, [C, <all others>. + *

+ * If two or more flavors share the best representation class, and that + * representation is one of the four explicitly listed, then one of those + * flavors will be chosen non-deterministically. If, however, no flavor has + * one of the four specified representations, the flavors will then be + * sorted by their charsets. Unicode charsets, such as "UTF-16", "UTF-8", + * "UTF-16BE", "UTF-16LE", and their aliases, are considered best. After + * them, the platform default charset and its aliases are selected. + * "US-ASCII" and its aliases are worst. All other charsets are chosen in + * alphabetical order, but only charsets supported by this implementation + * of the Java platform will be considered. + *

+ * If two or more flavors share the best charset, the flavors will then + * again be sorted by their representation classes in the following order: + * java.io.InputStream, java.nio.ByteBuffer, + * [B, <all others>. + *

+ * If two or more flavors share the best representation class, or if no + * flavor has one of the three specified representations, then one of those + * flavors will be chosen non-deterministically. + * + * @param availableFlavors an array of available DataFlavors + * @return the best (highest fidelity) flavor according to the rules + * specified above, or null, + * if availableFlavors is null, + * has zero length, or contains no text flavors + * @since 1.3 + */ + public static final DataFlavor selectBestTextFlavor( + DataFlavor[] availableFlavors) { + if (availableFlavors == null || availableFlavors.length == 0) { + return null; + } + + DataFlavor bestFlavor = Collections.max(Arrays.asList(availableFlavors), + DataFlavorUtil.getTextFlavorComparator()); + + if (!bestFlavor.isFlavorTextType()) { + return null; + } + + return bestFlavor; + } + + /** + * Gets a Reader for a text flavor, decoded, if necessary, for the expected + * charset (encoding). The supported representation classes are + * java.io.Reader, java.lang.String, + * java.nio.CharBuffer, [C, + * java.io.InputStream, java.nio.ByteBuffer, + * and [B. + *

+ * Because text flavors which do not support the charset parameter are + * encoded in a non-standard format, this method should not be called for + * such flavors. However, in order to maintain backward-compatibility, + * if this method is called for such a flavor, this method will treat the + * flavor as though it supports the charset parameter and attempt to + * decode it accordingly. See selectBestTextFlavor for a list + * of text flavors which do not support the charset parameter. + * + * @param transferable the Transferable whose data will be + * requested in this flavor + * + * @return a Reader to read the Transferable's + * data + * + * @exception IllegalArgumentException if the representation class + * is not one of the seven listed above + * @exception IllegalArgumentException if the Transferable + * has null data + * @exception NullPointerException if the Transferable is + * null + * @exception UnsupportedEncodingException if this flavor's representation + * is java.io.InputStream, + * java.nio.ByteBuffer, or [B and + * this flavor's encoding is not supported by this + * implementation of the Java platform + * @exception UnsupportedFlavorException if the Transferable + * does not support this flavor + * @exception IOException if the data cannot be read because of an + * I/O error + * @see #selectBestTextFlavor + * @since 1.3 + */ + public Reader getReaderForText(Transferable transferable) + throws UnsupportedFlavorException, IOException + { + Object transferObject = transferable.getTransferData(this); + if (transferObject == null) { + throw new IllegalArgumentException + ("getTransferData() returned null"); + } + + if (transferObject instanceof Reader) { + return (Reader)transferObject; + } else if (transferObject instanceof String) { + return new StringReader((String)transferObject); + } else if (transferObject instanceof CharBuffer) { + CharBuffer buffer = (CharBuffer)transferObject; + int size = buffer.remaining(); + char[] chars = new char[size]; + buffer.get(chars, 0, size); + return new CharArrayReader(chars); + } else if (transferObject instanceof char[]) { + return new CharArrayReader((char[])transferObject); + } + + InputStream stream = null; + + if (transferObject instanceof InputStream) { + stream = (InputStream)transferObject; + } else if (transferObject instanceof ByteBuffer) { + ByteBuffer buffer = (ByteBuffer)transferObject; + int size = buffer.remaining(); + byte[] bytes = new byte[size]; + buffer.get(bytes, 0, size); + stream = new ByteArrayInputStream(bytes); + } else if (transferObject instanceof byte[]) { + stream = new ByteArrayInputStream((byte[])transferObject); + } + + if (stream == null) { + throw new IllegalArgumentException("transfer data is not Reader, String, CharBuffer, char array, InputStream, ByteBuffer, or byte array"); + } + + String encoding = getParameter("charset"); + return (encoding == null) + ? new InputStreamReader(stream) + : new InputStreamReader(stream, encoding); + } + + /** + * Returns the MIME type string for this DataFlavor. + * @return the MIME type string for this flavor + */ + public String getMimeType() { + return (mimeType != null) ? mimeType.toString() : null; + } + + /** + * Returns the Class which objects supporting this + * DataFlavor will return when this DataFlavor + * is requested. + * @return the Class which objects supporting this + * DataFlavor will return when this DataFlavor + * is requested + */ + public Class getRepresentationClass() { + return representationClass; + } + + /** + * Returns the human presentable name for the data format that this + * DataFlavor represents. This name would be localized + * for different countries. + * @return the human presentable name for the data format that this + * DataFlavor represents + */ + public String getHumanPresentableName() { + return humanPresentableName; + } + + /** + * Returns the primary MIME type for this DataFlavor. + * @return the primary MIME type of this DataFlavor + */ + public String getPrimaryType() { + return (mimeType != null) ? mimeType.getPrimaryType() : null; + } + + /** + * Returns the sub MIME type of this DataFlavor. + * @return the Sub MIME type of this DataFlavor + */ + public String getSubType() { + return (mimeType != null) ? mimeType.getSubType() : null; + } + + /** + * Returns the human presentable name for this DataFlavor + * if paramName equals "humanPresentableName". Otherwise + * returns the MIME type value associated with paramName. + * + * @param paramName the parameter name requested + * @return the value of the name parameter, or null + * if there is no associated value + */ + public String getParameter(String paramName) { + if (paramName.equals("humanPresentableName")) { + return humanPresentableName; + } else { + return (mimeType != null) + ? mimeType.getParameter(paramName) : null; + } + } + + /** + * Sets the human presentable name for the data format that this + * DataFlavor represents. This name would be localized + * for different countries. + * @param humanPresentableName the new human presentable name + */ + public void setHumanPresentableName(String humanPresentableName) { + this.humanPresentableName = humanPresentableName; + } + + /** + * {@inheritDoc} + *

+ * The equals comparison for the {@code DataFlavor} class is implemented + * as follows: Two DataFlavors are considered equal if and + * only if their MIME primary type and subtype and representation class are + * equal. Additionally, if the primary type is "text", the subtype denotes + * a text flavor which supports the charset parameter, and the + * representation class is not java.io.Reader, + * java.lang.String, java.nio.CharBuffer, or + * [C, the charset parameter must also be equal. + * If a charset is not explicitly specified for one or both + * DataFlavors, the platform default encoding is assumed. See + * selectBestTextFlavor for a list of text flavors which + * support the charset parameter. + * + * @param o the Object to compare with this + * @return true if that is equivalent to this + * DataFlavor; false otherwise + * @see #selectBestTextFlavor + */ + public boolean equals(Object o) { + return ((o instanceof DataFlavor) && equals((DataFlavor)o)); + } + + /** + * This method has the same behavior as {@link #equals(Object)}. + * The only difference being that it takes a {@code DataFlavor} instance + * as a parameter. + * + * @param that the DataFlavor to compare with + * this + * @return true if that is equivalent to this + * DataFlavor; false otherwise + * @see #selectBestTextFlavor + */ + public boolean equals(DataFlavor that) { + if (that == null) { + return false; + } + if (this == that) { + return true; + } + + if (!Objects.equals(this.getRepresentationClass(), that.getRepresentationClass())) { + return false; + } + + if (mimeType == null) { + if (that.mimeType != null) { + return false; + } + } else { + if (!mimeType.match(that.mimeType)) { + return false; + } + + if ("text".equals(getPrimaryType())) { + if (DataFlavorUtil.doesSubtypeSupportCharset(this) + && representationClass != null + && !isStandardTextRepresentationClass()) { + String thisCharset = + DataFlavorUtil.canonicalName(this.getParameter("charset")); + String thatCharset = + DataFlavorUtil.canonicalName(that.getParameter("charset")); + if (!Objects.equals(thisCharset, thatCharset)) { + return false; + } + } + + if ("html".equals(getSubType())) { + String thisDocument = this.getParameter("document"); + String thatDocument = that.getParameter("document"); + if (!Objects.equals(thisDocument, thatDocument)) { + return false; + } + } + } + } + + return true; + } + + /** + * Compares only the mimeType against the passed in + * String and representationClass is + * not considered in the comparison. + * + * If representationClass needs to be compared, then + * equals(new DataFlavor(s)) may be used. + * @deprecated As inconsistent with hashCode() contract, + * use isMimeTypeEqual(String) instead. + * @param s the {@code mimeType} to compare. + * @return true if the String (MimeType) is equal; false otherwise or if + * {@code s} is {@code null} + */ + @Deprecated + public boolean equals(String s) { + if (s == null || mimeType == null) + return false; + return isMimeTypeEqual(s); + } + + /** + * Returns hash code for this DataFlavor. + * For two equal DataFlavors, hash codes are equal. + * For the String + * that matches DataFlavor.equals(String), it is not + * guaranteed that DataFlavor's hash code is equal + * to the hash code of the String. + * + * @return a hash code for this DataFlavor + */ + public int hashCode() { + int total = 0; + + if (representationClass != null) { + total += representationClass.hashCode(); + } + + if (mimeType != null) { + String primaryType = mimeType.getPrimaryType(); + if (primaryType != null) { + total += primaryType.hashCode(); + } + + // Do not add subType.hashCode() to the total. equals uses + // MimeType.match which reports a match if one or both of the + // subTypes is '*', regardless of the other subType. + + if ("text".equals(primaryType)) { + if (DataFlavorUtil.doesSubtypeSupportCharset(this) + && representationClass != null + && !isStandardTextRepresentationClass()) { + String charset = DataFlavorUtil.canonicalName(getParameter("charset")); + if (charset != null) { + total += charset.hashCode(); + } + } + + if ("html".equals(getSubType())) { + String document = this.getParameter("document"); + if (document != null) { + total += document.hashCode(); + } + } + } + } + + return total; + } + + /** + * Identical to {@link #equals(DataFlavor)}. + * + * @param that the DataFlavor to compare with + * this + * @return true if that is equivalent to this + * DataFlavor; false otherwise + * @see #selectBestTextFlavor + * @since 1.3 + */ + public boolean match(DataFlavor that) { + return equals(that); + } + + /** + * Returns whether the string representation of the MIME type passed in + * is equivalent to the MIME type of this DataFlavor. + * Parameters are not included in the comparison. + * + * @param mimeType the string representation of the MIME type + * @return true if the string representation of the MIME type passed in is + * equivalent to the MIME type of this DataFlavor; + * false otherwise + * @throws NullPointerException if mimeType is null + */ + public boolean isMimeTypeEqual(String mimeType) { + // JCK Test DataFlavor0117: if 'mimeType' is null, throw NPE + if (mimeType == null) { + throw new NullPointerException("mimeType"); + } + if (this.mimeType == null) { + return false; + } + try { + return this.mimeType.match(new MimeType(mimeType)); + } catch (MimeTypeParseException mtpe) { + return false; + } + } + + /** + * Compares the mimeType of two DataFlavor + * objects. No parameters are considered. + * + * @param dataFlavor the DataFlavor to be compared + * @return true if the MimeTypes are equal, + * otherwise false + */ + + public final boolean isMimeTypeEqual(DataFlavor dataFlavor) { + return isMimeTypeEqual(dataFlavor.mimeType); + } + + /** + * Compares the mimeType of two DataFlavor + * objects. No parameters are considered. + * + * @return true if the MimeTypes are equal, + * otherwise false + */ + + private boolean isMimeTypeEqual(MimeType mtype) { + if (this.mimeType == null) { + return (mtype == null); + } + return mimeType.match(mtype); + } + + /** + * Checks if the representation class is one of the standard text + * representation classes. + * + * @return true if the representation class is one of the standard text + * representation classes, otherwise false + */ + private boolean isStandardTextRepresentationClass() { + return isRepresentationClassReader() + || String.class.equals(representationClass) + || isRepresentationClassCharBuffer() + || char[].class.equals(representationClass); + } + + /** + * Does the DataFlavor represent a serialized object? + * @return whether or not a serialized object is represented + */ + public boolean isMimeTypeSerializedObject() { + return isMimeTypeEqual(javaSerializedObjectMimeType); + } + + /** + * Returns the default representation class. + * @return the default representation class + */ + public final Class getDefaultRepresentationClass() { + return ioInputStreamClass; + } + + /** + * Returns the name of the default representation class. + * @return the name of the default representation class + */ + public final String getDefaultRepresentationClassAsString() { + return getDefaultRepresentationClass().getName(); + } + + /** + * Does the DataFlavor represent a + * java.io.InputStream? + * @return whether or not this {@code DataFlavor} represent a + * {@code java.io.InputStream} + */ + public boolean isRepresentationClassInputStream() { + return ioInputStreamClass.isAssignableFrom(representationClass); + } + + /** + * Returns whether the representation class for this + * DataFlavor is java.io.Reader or a subclass + * thereof. + * @return whether or not the representation class for this + * {@code DataFlavor} is {@code java.io.Reader} or a subclass + * thereof + * + * @since 1.4 + */ + public boolean isRepresentationClassReader() { + return java.io.Reader.class.isAssignableFrom(representationClass); + } + + /** + * Returns whether the representation class for this + * DataFlavor is java.nio.CharBuffer or a + * subclass thereof. + * @return whether or not the representation class for this + * {@code DataFlavor} is {@code java.nio.CharBuffer} or a subclass + * thereof + * + * @since 1.4 + */ + public boolean isRepresentationClassCharBuffer() { + return java.nio.CharBuffer.class.isAssignableFrom(representationClass); + } + + /** + * Returns whether the representation class for this + * DataFlavor is java.nio.ByteBuffer or a + * subclass thereof. + * @return whether or not the representation class for this + * {@code DataFlavor} is {@code java.nio.ByteBuffer} or a subclass + * thereof + * + * @since 1.4 + */ + public boolean isRepresentationClassByteBuffer() { + return java.nio.ByteBuffer.class.isAssignableFrom(representationClass); + } + + /** + * Returns true if the representation class can be serialized. + * @return true if the representation class can be serialized + */ + + public boolean isRepresentationClassSerializable() { + return java.io.Serializable.class.isAssignableFrom(representationClass); + } + + /** + * Returns true if the representation class is Remote. + * @return true if the representation class is Remote + */ + public boolean isRepresentationClassRemote() { + return DataFlavorUtil.RMI.isRemote(representationClass); + } + + /** + * Returns true if the DataFlavor specified represents + * a serialized object. + * @return true if the DataFlavor specified represents + * a Serialized Object + */ + + public boolean isFlavorSerializedObjectType() { + return isRepresentationClassSerializable() && isMimeTypeEqual(javaSerializedObjectMimeType); + } + + /** + * Returns true if the DataFlavor specified represents + * a remote object. + * @return true if the DataFlavor specified represents + * a Remote Object + */ + + public boolean isFlavorRemoteObjectType() { + return isRepresentationClassRemote() + && isRepresentationClassSerializable() + && isMimeTypeEqual(javaRemoteObjectMimeType); + } + + + /** + * Returns true if the DataFlavor specified represents + * a list of file objects. + * @return true if the DataFlavor specified represents + * a List of File objects + */ + + public boolean isFlavorJavaFileListType() { + if (mimeType == null || representationClass == null) + return false; + return java.util.List.class.isAssignableFrom(representationClass) && + mimeType.match(javaFileListFlavor.mimeType); + + } + + /** + * Returns whether this DataFlavor is a valid text flavor for + * this implementation of the Java platform. Only flavors equivalent to + * DataFlavor.stringFlavor and DataFlavors with + * a primary MIME type of "text" can be valid text flavors. + *

+ * If this flavor supports the charset parameter, it must be equivalent to + * DataFlavor.stringFlavor, or its representation must be + * java.io.Reader, java.lang.String, + * java.nio.CharBuffer, [C, + * java.io.InputStream, java.nio.ByteBuffer, or + * [B. If the representation is + * java.io.InputStream, java.nio.ByteBuffer, or + * [B, then this flavor's charset parameter must + * be supported by this implementation of the Java platform. If a charset + * is not specified, then the platform default charset, which is always + * supported, is assumed. + *

+ * If this flavor does not support the charset parameter, its + * representation must be java.io.InputStream, + * java.nio.ByteBuffer, or [B. + *

+ * See selectBestTextFlavor for a list of text flavors which + * support the charset parameter. + * + * @return true if this DataFlavor is a valid + * text flavor as described above; false otherwise + * @see #selectBestTextFlavor + * @since 1.4 + */ + public boolean isFlavorTextType() { + return (DataFlavorUtil.isFlavorCharsetTextType(this) || + DataFlavorUtil.isFlavorNoncharsetTextType(this)); + } + + /** + * Serializes this DataFlavor. + */ + + public synchronized void writeExternal(ObjectOutput os) throws IOException { + if (mimeType != null) { + mimeType.setParameter("humanPresentableName", humanPresentableName); + os.writeObject(mimeType); + mimeType.removeParameter("humanPresentableName"); + } else { + os.writeObject(null); + } + + os.writeObject(representationClass); + } + + /** + * Restores this DataFlavor from a Serialized state. + */ + + public synchronized void readExternal(ObjectInput is) throws IOException , ClassNotFoundException { + String rcn = null; + mimeType = (MimeType)is.readObject(); + + if (mimeType != null) { + humanPresentableName = + mimeType.getParameter("humanPresentableName"); + mimeType.removeParameter("humanPresentableName"); + rcn = mimeType.getParameter("class"); + if (rcn == null) { + throw new IOException("no class parameter specified in: " + + mimeType); + } + } + + try { + representationClass = (Class)is.readObject(); + } catch (OptionalDataException ode) { + if (!ode.eof || ode.length != 0) { + throw ode; + } + // Ensure backward compatibility. + // Old versions didn't write the representation class to the stream. + if (rcn != null) { + representationClass = + DataFlavor.tryToLoadClass(rcn, getClass().getClassLoader()); + } + } + } + + /** + * Returns a clone of this DataFlavor. + * @return a clone of this DataFlavor + */ + + public Object clone() throws CloneNotSupportedException { + Object newObj = super.clone(); + if (mimeType != null) { + ((DataFlavor)newObj).mimeType = (MimeType)mimeType.clone(); + } + return newObj; + } // clone() + + /** + * Called on DataFlavor for every MIME Type parameter + * to allow DataFlavor subclasses to handle special + * parameters like the text/plain charset + * parameters, whose values are case insensitive. (MIME type parameter + * values are supposed to be case sensitive. + *

+ * This method is called for each parameter name/value pair and should + * return the normalized representation of the parameterValue. + * + * This method is never invoked by this implementation from 1.1 onwards. + * + * @param parameterName the parameter name + * @param parameterValue the parameter value + * @return the parameter value + * @deprecated + */ + @Deprecated + protected String normalizeMimeTypeParameter(String parameterName, String parameterValue) { + return parameterValue; + } + + /** + * Called for each MIME type string to give DataFlavor subtypes + * the opportunity to change how the normalization of MIME types is + * accomplished. One possible use would be to add default + * parameter/value pairs in cases where none are present in the MIME + * type string passed in. + * + * This method is never invoked by this implementation from 1.1 onwards. + * + * @param mimeType the mime type + * @return the mime type + * @deprecated + */ + @Deprecated + protected String normalizeMimeType(String mimeType) { + return mimeType; + } + + /* + * fields + */ + + /* placeholder for caching any platform-specific data for flavor */ + + transient int atom; + + /* Mime Type of DataFlavor */ + + MimeType mimeType; + + private String humanPresentableName; + + /** Java class of objects this DataFlavor represents **/ + + private Class representationClass; + +} // class DataFlavor --- old/src/java.desktop/share/classes/java/awt/datatransfer/FlavorEvent.java 2015-01-13 17:32:29.977496800 +0400 +++ /dev/null 2015-01-13 17:32:33.000000000 +0400 @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package java.awt.datatransfer; - -import java.util.EventObject; - - -/** - * FlavorEvent is used to notify interested parties - * that available {@link DataFlavor}s have changed in the - * {@link Clipboard} (the event source). - * - * @see FlavorListener - * - * @author Alexander Gerasimov - * @since 1.5 - */ -public class FlavorEvent extends EventObject { - private static final long serialVersionUID = -5842664112252414548L; - - /** - * Constructs a FlavorEvent object. - * - * @param source the Clipboard that is the source of the event - * - * @throws IllegalArgumentException if the {@code source} is {@code null} - */ - public FlavorEvent(Clipboard source) { - super(source); - } -} --- /dev/null 2015-01-13 17:32:33.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/FlavorEvent.java 2015-01-13 17:32:28.174393700 +0400 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.awt.datatransfer; + +import java.util.EventObject; + + +/** + * FlavorEvent is used to notify interested parties + * that available {@link DataFlavor}s have changed in the + * {@link Clipboard} (the event source). + * + * @see FlavorListener + * + * @author Alexander Gerasimov + * @since 1.5 + */ +public class FlavorEvent extends EventObject { + private static final long serialVersionUID = -5842664112252414548L; + + /** + * Constructs a FlavorEvent object. + * + * @param source the Clipboard that is the source of the event + * + * @throws IllegalArgumentException if the {@code source} is {@code null} + */ + public FlavorEvent(Clipboard source) { + super(source); + } +} --- old/src/java.desktop/share/classes/java/awt/datatransfer/FlavorListener.java 2015-01-13 17:32:46.497441700 +0400 +++ /dev/null 2015-01-13 17:32:51.000000000 +0400 @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package java.awt.datatransfer; - -import java.util.EventListener; - - -/** - * Defines an object which listens for {@link FlavorEvent}s. - * - * @author Alexander Gerasimov - * @since 1.5 - */ -public interface FlavorListener extends EventListener { - /** - * Invoked when the target {@link Clipboard} of the listener - * has changed its available {@link DataFlavor}s. - *

- * Some notifications may be redundant — they are not - * caused by a change of the set of DataFlavors available - * on the clipboard. - * For example, if the clipboard subsystem supposes that - * the system clipboard's contents has been changed but it - * can't ascertain whether its DataFlavors have been changed - * because of some exceptional condition when accessing the - * clipboard, the notification is sent to ensure from omitting - * a significant notification. Ordinarily, those redundant - * notifications should be occasional. - * - * @param e a FlavorEvent object - */ - void flavorsChanged(FlavorEvent e); -} --- /dev/null 2015-01-13 17:32:54.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/FlavorListener.java 2015-01-13 17:32:45.906407900 +0400 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.awt.datatransfer; + +import java.util.EventListener; + + +/** + * Defines an object which listens for {@link FlavorEvent}s. + * + * @author Alexander Gerasimov + * @since 1.5 + */ +public interface FlavorListener extends EventListener { + /** + * Invoked when the target {@link Clipboard} of the listener + * has changed its available {@link DataFlavor}s. + *

+ * Some notifications may be redundant — they are not + * caused by a change of the set of DataFlavors available + * on the clipboard. + * For example, if the clipboard subsystem supposes that + * the system clipboard's contents has been changed but it + * can't ascertain whether its DataFlavors have been changed + * because of some exceptional condition when accessing the + * clipboard, the notification is sent to ensure from omitting + * a significant notification. Ordinarily, those redundant + * notifications should be occasional. + * + * @param e a FlavorEvent object + */ + void flavorsChanged(FlavorEvent e); +} --- old/src/java.desktop/share/classes/java/awt/datatransfer/FlavorMap.java 2015-01-13 17:33:15.414095700 +0400 +++ /dev/null 2015-01-13 17:33:18.000000000 +0400 @@ -1,75 +0,0 @@ -/* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.awt.datatransfer; - -import java.util.Map; - - -/** - * A two-way Map between "natives" (Strings), which correspond to platform- - * specific data formats, and "flavors" (DataFlavors), which correspond to - * platform-independent MIME types. FlavorMaps need not be symmetric, but - * typically are. - * - * - * @since 1.2 - */ -public interface FlavorMap { - - /** - * Returns a Map of the specified DataFlavors to - * their corresponding String native. The returned - * Map is a modifiable copy of this FlavorMap's - * internal data. Client code is free to modify the Map - * without affecting this object. - * - * @param flavors an array of DataFlavors which will be the - * key set of the returned Map. If null is - * specified, a mapping of all DataFlavors currently - * known to this FlavorMap to their corresponding - * String natives will be returned. - * @return a java.util.Map of DataFlavors to - * String natives - */ - Map getNativesForFlavors(DataFlavor[] flavors); - - /** - * Returns a Map of the specified String natives - * to their corresponding DataFlavor. The returned - * Map is a modifiable copy of this FlavorMap's - * internal data. Client code is free to modify the Map - * without affecting this object. - * - * @param natives an array of Strings which will be the - * key set of the returned Map. If null is - * specified, a mapping of all String natives currently - * known to this FlavorMap to their corresponding - * DataFlavors will be returned. - * @return a java.util.Map of String natives to - * DataFlavors - */ - Map getFlavorsForNatives(String[] natives); -} --- /dev/null 2015-01-13 17:33:18.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/FlavorMap.java 2015-01-13 17:33:12.650937600 +0400 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.awt.datatransfer; + +import java.util.Map; + + +/** + * A two-way Map between "natives" (Strings), which correspond to platform- + * specific data formats, and "flavors" (DataFlavors), which correspond to + * platform-independent MIME types. FlavorMaps need not be symmetric, but + * typically are. + * + * + * @since 1.2 + */ +public interface FlavorMap { + + /** + * Returns a Map of the specified DataFlavors to + * their corresponding String native. The returned + * Map is a modifiable copy of this FlavorMap's + * internal data. Client code is free to modify the Map + * without affecting this object. + * + * @param flavors an array of DataFlavors which will be the + * key set of the returned Map. If null is + * specified, a mapping of all DataFlavors currently + * known to this FlavorMap to their corresponding + * String natives will be returned. + * @return a java.util.Map of DataFlavors to + * String natives + */ + Map getNativesForFlavors(DataFlavor[] flavors); + + /** + * Returns a Map of the specified String natives + * to their corresponding DataFlavor. The returned + * Map is a modifiable copy of this FlavorMap's + * internal data. Client code is free to modify the Map + * without affecting this object. + * + * @param natives an array of Strings which will be the + * key set of the returned Map. If null is + * specified, a mapping of all String natives currently + * known to this FlavorMap to their corresponding + * DataFlavors will be returned. + * @return a java.util.Map of String natives to + * DataFlavors + */ + Map getFlavorsForNatives(String[] natives); +} --- old/src/java.desktop/share/classes/java/awt/datatransfer/FlavorTable.java 2015-01-13 17:33:25.315662000 +0400 +++ /dev/null 2015-01-13 17:33:26.000000000 +0400 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.awt.datatransfer; - -import java.util.List; - - -/** - * A FlavorMap which relaxes the traditional 1-to-1 restriction of a Map. A - * flavor is permitted to map to any number of natives, and likewise a native - * is permitted to map to any number of flavors. FlavorTables need not be - * symmetric, but typically are. - * - * @author David Mendenhall - * - * @since 1.4 - */ -public interface FlavorTable extends FlavorMap { - - /** - * Returns a List of String natives to which the - * specified DataFlavor corresponds. The List - * will be sorted from best native to worst. That is, the first native will - * best reflect data in the specified flavor to the underlying native - * platform. The returned List is a modifiable copy of this - * FlavorTable's internal data. Client code is free to modify - * the List without affecting this object. - * - * @param flav the DataFlavor whose corresponding natives - * should be returned. If null is specified, all - * natives currently known to this FlavorTable are - * returned in a non-deterministic order. - * @return a java.util.List of java.lang.String - * objects which are platform-specific representations of platform- - * specific data formats - */ - List getNativesForFlavor(DataFlavor flav); - - /** - * Returns a List of DataFlavors to which the - * specified String corresponds. The List will be - * sorted from best DataFlavor to worst. That is, the first - * DataFlavor will best reflect data in the specified - * native to a Java application. The returned List is a - * modifiable copy of this FlavorTable's internal data. - * Client code is free to modify the List without affecting - * this object. - * - * @param nat the native whose corresponding DataFlavors - * should be returned. If null is specified, all - * DataFlavors currently known to this - * FlavorTable are returned in a non-deterministic - * order. - * @return a java.util.List of DataFlavor - * objects into which platform-specific data in the specified, - * platform-specific native can be translated - */ - List getFlavorsForNative(String nat); -} --- /dev/null 2015-01-13 17:33:26.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/FlavorTable.java 2015-01-13 17:33:24.705627100 +0400 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.awt.datatransfer; + +import java.util.List; + + +/** + * A FlavorMap which relaxes the traditional 1-to-1 restriction of a Map. A + * flavor is permitted to map to any number of natives, and likewise a native + * is permitted to map to any number of flavors. FlavorTables need not be + * symmetric, but typically are. + * + * @author David Mendenhall + * + * @since 1.4 + */ +public interface FlavorTable extends FlavorMap { + + /** + * Returns a List of String natives to which the + * specified DataFlavor corresponds. The List + * will be sorted from best native to worst. That is, the first native will + * best reflect data in the specified flavor to the underlying native + * platform. The returned List is a modifiable copy of this + * FlavorTable's internal data. Client code is free to modify + * the List without affecting this object. + * + * @param flav the DataFlavor whose corresponding natives + * should be returned. If null is specified, all + * natives currently known to this FlavorTable are + * returned in a non-deterministic order. + * @return a java.util.List of java.lang.String + * objects which are platform-specific representations of platform- + * specific data formats + */ + List getNativesForFlavor(DataFlavor flav); + + /** + * Returns a List of DataFlavors to which the + * specified String corresponds. The List will be + * sorted from best DataFlavor to worst. That is, the first + * DataFlavor will best reflect data in the specified + * native to a Java application. The returned List is a + * modifiable copy of this FlavorTable's internal data. + * Client code is free to modify the List without affecting + * this object. + * + * @param nat the native whose corresponding DataFlavors + * should be returned. If null is specified, all + * DataFlavors currently known to this + * FlavorTable are returned in a non-deterministic + * order. + * @return a java.util.List of DataFlavor + * objects into which platform-specific data in the specified, + * platform-specific native can be translated + */ + List getFlavorsForNative(String nat); +} --- old/src/java.desktop/share/classes/java/awt/datatransfer/MimeType.java 2015-01-13 17:33:36.880323500 +0400 +++ /dev/null 2015-01-13 17:33:38.000000000 +0400 @@ -1,394 +0,0 @@ -/* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.awt.datatransfer; - -import java.io.Externalizable; -import java.io.ObjectOutput; -import java.io.ObjectInput; -import java.io.IOException; -import java.util.Enumeration; -import java.util.Locale; - - -/** - * A Multipurpose Internet Mail Extension (MIME) type, as defined - * in RFC 2045 and 2046. - * - * THIS IS *NOT* - REPEAT *NOT* - A PUBLIC CLASS! DataFlavor IS - * THE PUBLIC INTERFACE, AND THIS IS PROVIDED AS A ***PRIVATE*** - * (THAT IS AS IN *NOT* PUBLIC) HELPER CLASS! - */ -class MimeType implements Externalizable, Cloneable { - - /* - * serialization support - */ - - static final long serialVersionUID = -6568722458793895906L; - - /** - * Constructor for externalization; this constructor should not be - * called directly by an application, since the result will be an - * uninitialized, immutable MimeType object. - */ - public MimeType() { - } - - /** - * Builds a MimeType from a String. - * - * @param rawdata text used to initialize the MimeType - * @throws NullPointerException if rawdata is null - */ - public MimeType(String rawdata) throws MimeTypeParseException { - parse(rawdata); - } - - /** - * Builds a MimeType with the given primary and sub - * type but has an empty parameter list. - * - * @param primary the primary type of this MimeType - * @param sub the subtype of this MimeType - * @throws NullPointerException if either primary or - * sub is null - */ - public MimeType(String primary, String sub) throws MimeTypeParseException { - this(primary, sub, new MimeTypeParameterList()); - } - - /** - * Builds a MimeType with a pre-defined - * and valid (or empty) parameter list. - * - * @param primary the primary type of this MimeType - * @param sub the subtype of this MimeType - * @param mtpl the requested parameter list - * @throws NullPointerException if either primary, - * sub or mtpl is null - */ - public MimeType(String primary, String sub, MimeTypeParameterList mtpl) throws -MimeTypeParseException { - // check to see if primary is valid - if(isValidToken(primary)) { - primaryType = primary.toLowerCase(Locale.ENGLISH); - } else { - throw new MimeTypeParseException("Primary type is invalid."); - } - - // check to see if sub is valid - if(isValidToken(sub)) { - subType = sub.toLowerCase(Locale.ENGLISH); - } else { - throw new MimeTypeParseException("Sub type is invalid."); - } - - parameters = (MimeTypeParameterList)mtpl.clone(); - } - - public int hashCode() { - - // We sum up the hash codes for all of the strings. This - // way, the order of the strings is irrelevant - int code = 0; - code += primaryType.hashCode(); - code += subType.hashCode(); - code += parameters.hashCode(); - return code; - } // hashCode() - - /** - * MimeTypes are equal if their primary types, - * subtypes, and parameters are all equal. No default values - * are taken into account. - * @param thatObject the object to be evaluated as a - * MimeType - * @return true if thatObject is - * a MimeType; otherwise returns false - */ - public boolean equals(Object thatObject) { - if (!(thatObject instanceof MimeType)) { - return false; - } - MimeType that = (MimeType)thatObject; - boolean isIt = - ((this.primaryType.equals(that.primaryType)) && - (this.subType.equals(that.subType)) && - (this.parameters.equals(that.parameters))); - return isIt; - } // equals() - - /** - * A routine for parsing the MIME type out of a String. - * - * @throws NullPointerException if rawdata is null - */ - private void parse(String rawdata) throws MimeTypeParseException { - int slashIndex = rawdata.indexOf('/'); - int semIndex = rawdata.indexOf(';'); - if((slashIndex < 0) && (semIndex < 0)) { - // neither character is present, so treat it - // as an error - throw new MimeTypeParseException("Unable to find a sub type."); - } else if((slashIndex < 0) && (semIndex >= 0)) { - // we have a ';' (and therefore a parameter list), - // but no '/' indicating a sub type is present - throw new MimeTypeParseException("Unable to find a sub type."); - } else if((slashIndex >= 0) && (semIndex < 0)) { - // we have a primary and sub type but no parameter list - primaryType = rawdata.substring(0,slashIndex). - trim().toLowerCase(Locale.ENGLISH); - subType = rawdata.substring(slashIndex + 1). - trim().toLowerCase(Locale.ENGLISH); - parameters = new MimeTypeParameterList(); - } else if (slashIndex < semIndex) { - // we have all three items in the proper sequence - primaryType = rawdata.substring(0, slashIndex). - trim().toLowerCase(Locale.ENGLISH); - subType = rawdata.substring(slashIndex + 1, - semIndex).trim().toLowerCase(Locale.ENGLISH); - parameters = new -MimeTypeParameterList(rawdata.substring(semIndex)); - } else { - // we have a ';' lexically before a '/' which means we have a primary type - // & a parameter list but no sub type - throw new MimeTypeParseException("Unable to find a sub type."); - } - - // now validate the primary and sub types - - // check to see if primary is valid - if(!isValidToken(primaryType)) { - throw new MimeTypeParseException("Primary type is invalid."); - } - - // check to see if sub is valid - if(!isValidToken(subType)) { - throw new MimeTypeParseException("Sub type is invalid."); - } - } - - /** - * Retrieve the primary type of this object. - */ - public String getPrimaryType() { - return primaryType; - } - - /** - * Retrieve the sub type of this object. - */ - public String getSubType() { - return subType; - } - - /** - * Retrieve a copy of this object's parameter list. - */ - public MimeTypeParameterList getParameters() { - return (MimeTypeParameterList)parameters.clone(); - } - - /** - * Retrieve the value associated with the given name, or null if there - * is no current association. - */ - public String getParameter(String name) { - return parameters.get(name); - } - - /** - * Set the value to be associated with the given name, replacing - * any previous association. - * - * @throw IllegalArgumentException if parameter or value is illegal - */ - public void setParameter(String name, String value) { - parameters.set(name, value); - } - - /** - * Remove any value associated with the given name. - * - * @throw IllegalArgumentException if parameter may not be deleted - */ - public void removeParameter(String name) { - parameters.remove(name); - } - - /** - * Return the String representation of this object. - */ - public String toString() { - return getBaseType() + parameters.toString(); - } - - /** - * Return a String representation of this object - * without the parameter list. - */ - public String getBaseType() { - return primaryType + "/" + subType; - } - - /** - * Returns true if the primary type and the - * subtype of this object are the same as the specified - * type; otherwise returns false. - * - * @param type the type to compare to this's type - * @return true if the primary type and the - * subtype of this object are the same as the - * specified type; otherwise returns - * false - */ - public boolean match(MimeType type) { - if (type == null) - return false; - return primaryType.equals(type.getPrimaryType()) - && (subType.equals("*") - || type.getSubType().equals("*") - || (subType.equals(type.getSubType()))); - } - - /** - * Returns true if the primary type and the - * subtype of this object are the same as the content type - * described in rawdata; otherwise returns - * false. - * - * @param rawdata the raw data to be examined - * @return true if the primary type and the - * subtype of this object are the same as the content type - * described in rawdata; otherwise returns - * false; if rawdata is - * null, returns false - */ - public boolean match(String rawdata) throws MimeTypeParseException { - if (rawdata == null) - return false; - return match(new MimeType(rawdata)); - } - - /** - * The object implements the writeExternal method to save its contents - * by calling the methods of DataOutput for its primitive values or - * calling the writeObject method of ObjectOutput for objects, strings - * and arrays. - * @exception IOException Includes any I/O exceptions that may occur - */ - public void writeExternal(ObjectOutput out) throws IOException { - String s = toString(); // contains ASCII chars only - // one-to-one correspondence between ASCII char and byte in UTF string - if (s.length() <= 65535) { // 65535 is max length of UTF string - out.writeUTF(s); - } else { - out.writeByte(0); - out.writeByte(0); - out.writeInt(s.length()); - out.write(s.getBytes()); - } - } - - /** - * The object implements the readExternal method to restore its - * contents by calling the methods of DataInput for primitive - * types and readObject for objects, strings and arrays. The - * readExternal method must read the values in the same sequence - * and with the same types as were written by writeExternal. - * @exception ClassNotFoundException If the class for an object being - * restored cannot be found. - */ - public void readExternal(ObjectInput in) throws IOException, -ClassNotFoundException { - String s = in.readUTF(); - if (s == null || s.length() == 0) { // long mime type - byte[] ba = new byte[in.readInt()]; - in.readFully(ba); - s = new String(ba); - } - try { - parse(s); - } catch(MimeTypeParseException e) { - throw new IOException(e.toString()); - } - } - - /** - * Returns a clone of this object. - * @return a clone of this object - */ - - public Object clone() { - MimeType newObj = null; - try { - newObj = (MimeType)super.clone(); - } catch (CloneNotSupportedException cannotHappen) { - } - newObj.parameters = (MimeTypeParameterList)parameters.clone(); - return newObj; - } - - private String primaryType; - private String subType; - private MimeTypeParameterList parameters; - - // below here be scary parsing related things - - /** - * Determines whether or not a given character belongs to a legal token. - */ - private static boolean isTokenChar(char c) { - return ((c > 040) && (c < 0177)) && (TSPECIALS.indexOf(c) < 0); - } - - /** - * Determines whether or not a given string is a legal token. - * - * @throws NullPointerException if s is null - */ - private boolean isValidToken(String s) { - int len = s.length(); - if(len > 0) { - for (int i = 0; i < len; ++i) { - char c = s.charAt(i); - if (!isTokenChar(c)) { - return false; - } - } - return true; - } else { - return false; - } - } - - /** - * A string that holds all the special chars. - */ - - private static final String TSPECIALS = "()<>@,;:\\\"/[]?="; - -} // class MimeType --- /dev/null 2015-01-13 17:33:38.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/MimeType.java 2015-01-13 17:33:35.201227400 +0400 @@ -0,0 +1,394 @@ +/* + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.awt.datatransfer; + +import java.io.Externalizable; +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Locale; + + +/** + * A Multipurpose Internet Mail Extension (MIME) type, as defined + * in RFC 2045 and 2046. + * + * THIS IS *NOT* - REPEAT *NOT* - A PUBLIC CLASS! DataFlavor IS + * THE PUBLIC INTERFACE, AND THIS IS PROVIDED AS A ***PRIVATE*** + * (THAT IS AS IN *NOT* PUBLIC) HELPER CLASS! + */ +class MimeType implements Externalizable, Cloneable { + + /* + * serialization support + */ + + static final long serialVersionUID = -6568722458793895906L; + + /** + * Constructor for externalization; this constructor should not be + * called directly by an application, since the result will be an + * uninitialized, immutable MimeType object. + */ + public MimeType() { + } + + /** + * Builds a MimeType from a String. + * + * @param rawdata text used to initialize the MimeType + * @throws NullPointerException if rawdata is null + */ + public MimeType(String rawdata) throws MimeTypeParseException { + parse(rawdata); + } + + /** + * Builds a MimeType with the given primary and sub + * type but has an empty parameter list. + * + * @param primary the primary type of this MimeType + * @param sub the subtype of this MimeType + * @throws NullPointerException if either primary or + * sub is null + */ + public MimeType(String primary, String sub) throws MimeTypeParseException { + this(primary, sub, new MimeTypeParameterList()); + } + + /** + * Builds a MimeType with a pre-defined + * and valid (or empty) parameter list. + * + * @param primary the primary type of this MimeType + * @param sub the subtype of this MimeType + * @param mtpl the requested parameter list + * @throws NullPointerException if either primary, + * sub or mtpl is null + */ + public MimeType(String primary, String sub, MimeTypeParameterList mtpl) throws +MimeTypeParseException { + // check to see if primary is valid + if(isValidToken(primary)) { + primaryType = primary.toLowerCase(Locale.ENGLISH); + } else { + throw new MimeTypeParseException("Primary type is invalid."); + } + + // check to see if sub is valid + if(isValidToken(sub)) { + subType = sub.toLowerCase(Locale.ENGLISH); + } else { + throw new MimeTypeParseException("Sub type is invalid."); + } + + parameters = (MimeTypeParameterList)mtpl.clone(); + } + + public int hashCode() { + + // We sum up the hash codes for all of the strings. This + // way, the order of the strings is irrelevant + int code = 0; + code += primaryType.hashCode(); + code += subType.hashCode(); + code += parameters.hashCode(); + return code; + } // hashCode() + + /** + * MimeTypes are equal if their primary types, + * subtypes, and parameters are all equal. No default values + * are taken into account. + * @param thatObject the object to be evaluated as a + * MimeType + * @return true if thatObject is + * a MimeType; otherwise returns false + */ + public boolean equals(Object thatObject) { + if (!(thatObject instanceof MimeType)) { + return false; + } + MimeType that = (MimeType)thatObject; + boolean isIt = + ((this.primaryType.equals(that.primaryType)) && + (this.subType.equals(that.subType)) && + (this.parameters.equals(that.parameters))); + return isIt; + } // equals() + + /** + * A routine for parsing the MIME type out of a String. + * + * @throws NullPointerException if rawdata is null + */ + private void parse(String rawdata) throws MimeTypeParseException { + int slashIndex = rawdata.indexOf('/'); + int semIndex = rawdata.indexOf(';'); + if((slashIndex < 0) && (semIndex < 0)) { + // neither character is present, so treat it + // as an error + throw new MimeTypeParseException("Unable to find a sub type."); + } else if((slashIndex < 0) && (semIndex >= 0)) { + // we have a ';' (and therefore a parameter list), + // but no '/' indicating a sub type is present + throw new MimeTypeParseException("Unable to find a sub type."); + } else if((slashIndex >= 0) && (semIndex < 0)) { + // we have a primary and sub type but no parameter list + primaryType = rawdata.substring(0,slashIndex). + trim().toLowerCase(Locale.ENGLISH); + subType = rawdata.substring(slashIndex + 1). + trim().toLowerCase(Locale.ENGLISH); + parameters = new MimeTypeParameterList(); + } else if (slashIndex < semIndex) { + // we have all three items in the proper sequence + primaryType = rawdata.substring(0, slashIndex). + trim().toLowerCase(Locale.ENGLISH); + subType = rawdata.substring(slashIndex + 1, + semIndex).trim().toLowerCase(Locale.ENGLISH); + parameters = new +MimeTypeParameterList(rawdata.substring(semIndex)); + } else { + // we have a ';' lexically before a '/' which means we have a primary type + // & a parameter list but no sub type + throw new MimeTypeParseException("Unable to find a sub type."); + } + + // now validate the primary and sub types + + // check to see if primary is valid + if(!isValidToken(primaryType)) { + throw new MimeTypeParseException("Primary type is invalid."); + } + + // check to see if sub is valid + if(!isValidToken(subType)) { + throw new MimeTypeParseException("Sub type is invalid."); + } + } + + /** + * Retrieve the primary type of this object. + */ + public String getPrimaryType() { + return primaryType; + } + + /** + * Retrieve the sub type of this object. + */ + public String getSubType() { + return subType; + } + + /** + * Retrieve a copy of this object's parameter list. + */ + public MimeTypeParameterList getParameters() { + return (MimeTypeParameterList)parameters.clone(); + } + + /** + * Retrieve the value associated with the given name, or null if there + * is no current association. + */ + public String getParameter(String name) { + return parameters.get(name); + } + + /** + * Set the value to be associated with the given name, replacing + * any previous association. + * + * @throw IllegalArgumentException if parameter or value is illegal + */ + public void setParameter(String name, String value) { + parameters.set(name, value); + } + + /** + * Remove any value associated with the given name. + * + * @throw IllegalArgumentException if parameter may not be deleted + */ + public void removeParameter(String name) { + parameters.remove(name); + } + + /** + * Return the String representation of this object. + */ + public String toString() { + return getBaseType() + parameters.toString(); + } + + /** + * Return a String representation of this object + * without the parameter list. + */ + public String getBaseType() { + return primaryType + "/" + subType; + } + + /** + * Returns true if the primary type and the + * subtype of this object are the same as the specified + * type; otherwise returns false. + * + * @param type the type to compare to this's type + * @return true if the primary type and the + * subtype of this object are the same as the + * specified type; otherwise returns + * false + */ + public boolean match(MimeType type) { + if (type == null) + return false; + return primaryType.equals(type.getPrimaryType()) + && (subType.equals("*") + || type.getSubType().equals("*") + || (subType.equals(type.getSubType()))); + } + + /** + * Returns true if the primary type and the + * subtype of this object are the same as the content type + * described in rawdata; otherwise returns + * false. + * + * @param rawdata the raw data to be examined + * @return true if the primary type and the + * subtype of this object are the same as the content type + * described in rawdata; otherwise returns + * false; if rawdata is + * null, returns false + */ + public boolean match(String rawdata) throws MimeTypeParseException { + if (rawdata == null) + return false; + return match(new MimeType(rawdata)); + } + + /** + * The object implements the writeExternal method to save its contents + * by calling the methods of DataOutput for its primitive values or + * calling the writeObject method of ObjectOutput for objects, strings + * and arrays. + * @exception IOException Includes any I/O exceptions that may occur + */ + public void writeExternal(ObjectOutput out) throws IOException { + String s = toString(); // contains ASCII chars only + // one-to-one correspondence between ASCII char and byte in UTF string + if (s.length() <= 65535) { // 65535 is max length of UTF string + out.writeUTF(s); + } else { + out.writeByte(0); + out.writeByte(0); + out.writeInt(s.length()); + out.write(s.getBytes()); + } + } + + /** + * The object implements the readExternal method to restore its + * contents by calling the methods of DataInput for primitive + * types and readObject for objects, strings and arrays. The + * readExternal method must read the values in the same sequence + * and with the same types as were written by writeExternal. + * @exception ClassNotFoundException If the class for an object being + * restored cannot be found. + */ + public void readExternal(ObjectInput in) throws IOException, +ClassNotFoundException { + String s = in.readUTF(); + if (s == null || s.length() == 0) { // long mime type + byte[] ba = new byte[in.readInt()]; + in.readFully(ba); + s = new String(ba); + } + try { + parse(s); + } catch(MimeTypeParseException e) { + throw new IOException(e.toString()); + } + } + + /** + * Returns a clone of this object. + * @return a clone of this object + */ + + public Object clone() { + MimeType newObj = null; + try { + newObj = (MimeType)super.clone(); + } catch (CloneNotSupportedException cannotHappen) { + } + newObj.parameters = (MimeTypeParameterList)parameters.clone(); + return newObj; + } + + private String primaryType; + private String subType; + private MimeTypeParameterList parameters; + + // below here be scary parsing related things + + /** + * Determines whether or not a given character belongs to a legal token. + */ + private static boolean isTokenChar(char c) { + return ((c > 040) && (c < 0177)) && (TSPECIALS.indexOf(c) < 0); + } + + /** + * Determines whether or not a given string is a legal token. + * + * @throws NullPointerException if s is null + */ + private boolean isValidToken(String s) { + int len = s.length(); + if(len > 0) { + for (int i = 0; i < len; ++i) { + char c = s.charAt(i); + if (!isTokenChar(c)) { + return false; + } + } + return true; + } else { + return false; + } + } + + /** + * A string that holds all the special chars. + */ + + private static final String TSPECIALS = "()<>@,;:\\\"/[]?="; + +} // class MimeType --- old/src/java.desktop/share/classes/java/awt/datatransfer/MimeTypeParameterList.java 2015-01-13 17:33:50.060077300 +0400 +++ /dev/null 2015-01-13 17:33:59.000000000 +0400 @@ -1,404 +0,0 @@ -/* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.awt.datatransfer; - -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - - -/** - * An object that encapsulates the parameter list of a MimeType - * as defined in RFC 2045 and 2046. - * - * @author jeff.dunn@eng.sun.com - */ -class MimeTypeParameterList implements Cloneable { - - /** - * Default constructor. - */ - public MimeTypeParameterList() { - parameters = new Hashtable<>(); - } - - public MimeTypeParameterList(String rawdata) - throws MimeTypeParseException - { - parameters = new Hashtable<>(); - - // now parse rawdata - parse(rawdata); - } - - public int hashCode() { - int code = Integer.MAX_VALUE/45; // "random" value for empty lists - String paramName = null; - Enumeration enum_ = this.getNames(); - - while (enum_.hasMoreElements()) { - paramName = enum_.nextElement(); - code += paramName.hashCode(); - code += this.get(paramName).hashCode(); - } - - return code; - } // hashCode() - - /** - * Two parameter lists are considered equal if they have exactly - * the same set of parameter names and associated values. The - * order of the parameters is not considered. - */ - public boolean equals(Object thatObject) { - //System.out.println("MimeTypeParameterList.equals("+this+","+thatObject+")"); - if (!(thatObject instanceof MimeTypeParameterList)) { - return false; - } - MimeTypeParameterList that = (MimeTypeParameterList)thatObject; - if (this.size() != that.size()) { - return false; - } - String name = null; - String thisValue = null; - String thatValue = null; - Set> entries = parameters.entrySet(); - Iterator> iterator = entries.iterator(); - Map.Entry entry = null; - while (iterator.hasNext()) { - entry = iterator.next(); - name = entry.getKey(); - thisValue = entry.getValue(); - thatValue = that.parameters.get(name); - if ((thisValue == null) || (thatValue == null)) { - // both null -> equal, only one null -> not equal - if (thisValue != thatValue) { - return false; - } - } else if (!thisValue.equals(thatValue)) { - return false; - } - } // while iterator - - return true; - } // equals() - - /** - * A routine for parsing the parameter list out of a String. - */ - protected void parse(String rawdata) throws MimeTypeParseException { - int length = rawdata.length(); - if(length > 0) { - int currentIndex = skipWhiteSpace(rawdata, 0); - int lastIndex = 0; - - if(currentIndex < length) { - char currentChar = rawdata.charAt(currentIndex); - while ((currentIndex < length) && (currentChar == ';')) { - String name; - String value; - boolean foundit; - - // eat the ';' - ++currentIndex; - - // now parse the parameter name - - // skip whitespace - currentIndex = skipWhiteSpace(rawdata, currentIndex); - - if(currentIndex < length) { - // find the end of the token char run - lastIndex = currentIndex; - currentChar = rawdata.charAt(currentIndex); - while((currentIndex < length) && isTokenChar(currentChar)) { - ++currentIndex; - currentChar = rawdata.charAt(currentIndex); - } - name = rawdata.substring(lastIndex, currentIndex).toLowerCase(); - - // now parse the '=' that separates the name from the value - - // skip whitespace - currentIndex = skipWhiteSpace(rawdata, currentIndex); - - if((currentIndex < length) && (rawdata.charAt(currentIndex) == '=')) { - // eat it and parse the parameter value - ++currentIndex; - - // skip whitespace - currentIndex = skipWhiteSpace(rawdata, currentIndex); - - if(currentIndex < length) { - // now find out whether or not we have a quoted value - currentChar = rawdata.charAt(currentIndex); - if(currentChar == '"') { - // yup it's quoted so eat it and capture the quoted string - ++currentIndex; - lastIndex = currentIndex; - - if(currentIndex < length) { - // find the next unescaped quote - foundit = false; - while((currentIndex < length) && !foundit) { - currentChar = rawdata.charAt(currentIndex); - if(currentChar == '\\') { - // found an escape sequence so pass this and the next character - currentIndex += 2; - } else if(currentChar == '"') { - // found it! - foundit = true; - } else { - ++currentIndex; - } - } - if(currentChar == '"') { - value = unquote(rawdata.substring(lastIndex, currentIndex)); - // eat the quote - ++currentIndex; - } else { - throw new MimeTypeParseException("Encountered unterminated quoted parameter value."); - } - } else { - throw new MimeTypeParseException("Encountered unterminated quoted parameter value."); - } - } else if(isTokenChar(currentChar)) { - // nope it's an ordinary token so it ends with a non-token char - lastIndex = currentIndex; - foundit = false; - while((currentIndex < length) && !foundit) { - currentChar = rawdata.charAt(currentIndex); - - if(isTokenChar(currentChar)) { - ++currentIndex; - } else { - foundit = true; - } - } - value = rawdata.substring(lastIndex, currentIndex); - } else { - // it ain't a value - throw new MimeTypeParseException("Unexpected character encountered at index " + currentIndex); - } - - // now put the data into the hashtable - parameters.put(name, value); - } else { - throw new MimeTypeParseException("Couldn't find a value for parameter named " + name); - } - } else { - throw new MimeTypeParseException("Couldn't find the '=' that separates a parameter name from its value."); - } - } else { - throw new MimeTypeParseException("Couldn't find parameter name"); - } - - // setup the next iteration - currentIndex = skipWhiteSpace(rawdata, currentIndex); - if(currentIndex < length) { - currentChar = rawdata.charAt(currentIndex); - } - } - if(currentIndex < length) { - throw new MimeTypeParseException("More characters encountered in input than expected."); - } - } - } - } - - /** - * return the number of name-value pairs in this list. - */ - public int size() { - return parameters.size(); - } - - /** - * Determine whether or not this list is empty. - */ - public boolean isEmpty() { - return parameters.isEmpty(); - } - - /** - * Retrieve the value associated with the given name, or null if there - * is no current association. - */ - public String get(String name) { - return parameters.get(name.trim().toLowerCase()); - } - - /** - * Set the value to be associated with the given name, replacing - * any previous association. - */ - public void set(String name, String value) { - parameters.put(name.trim().toLowerCase(), value); - } - - /** - * Remove any value associated with the given name. - */ - public void remove(String name) { - parameters.remove(name.trim().toLowerCase()); - } - - /** - * Retrieve an enumeration of all the names in this list. - */ - public Enumeration getNames() { - return parameters.keys(); - } - - public String toString() { - // Heuristic: 8 characters per field - StringBuilder buffer = new StringBuilder(parameters.size() * 16); - - Enumeration keys = parameters.keys(); - while(keys.hasMoreElements()) - { - buffer.append("; "); - - String key = keys.nextElement(); - buffer.append(key); - buffer.append('='); - buffer.append(quote(parameters.get(key))); - } - - return buffer.toString(); - } - - /** - * @return a clone of this object - */ - @SuppressWarnings("unchecked") // Cast from clone - public Object clone() { - MimeTypeParameterList newObj = null; - try { - newObj = (MimeTypeParameterList)super.clone(); - } catch (CloneNotSupportedException cannotHappen) { - } - newObj.parameters = (Hashtable)parameters.clone(); - return newObj; - } - - private Hashtable parameters; - - // below here be scary parsing related things - - /** - * Determine whether or not a given character belongs to a legal token. - */ - private static boolean isTokenChar(char c) { - return ((c > 040) && (c < 0177)) && (TSPECIALS.indexOf(c) < 0); - } - - /** - * return the index of the first non white space character in - * rawdata at or after index i. - */ - private static int skipWhiteSpace(String rawdata, int i) { - int length = rawdata.length(); - if (i < length) { - char c = rawdata.charAt(i); - while ((i < length) && Character.isWhitespace(c)) { - ++i; - c = rawdata.charAt(i); - } - } - - return i; - } - - /** - * A routine that knows how and when to quote and escape the given value. - */ - private static String quote(String value) { - boolean needsQuotes = false; - - // check to see if we actually have to quote this thing - int length = value.length(); - for(int i = 0; (i < length) && !needsQuotes; ++i) { - needsQuotes = !isTokenChar(value.charAt(i)); - } - - if(needsQuotes) { - StringBuilder buffer = new StringBuilder((int)(length * 1.5)); - - // add the initial quote - buffer.append('"'); - - // add the properly escaped text - for(int i = 0; i < length; ++i) { - char c = value.charAt(i); - if((c == '\\') || (c == '"')) { - buffer.append('\\'); - } - buffer.append(c); - } - - // add the closing quote - buffer.append('"'); - - return buffer.toString(); - } - else - { - return value; - } - } - - /** - * A routine that knows how to strip the quotes and escape sequences from the given value. - */ - private static String unquote(String value) { - int valueLength = value.length(); - StringBuilder buffer = new StringBuilder(valueLength); - - boolean escaped = false; - for(int i = 0; i < valueLength; ++i) { - char currentChar = value.charAt(i); - if(!escaped && (currentChar != '\\')) { - buffer.append(currentChar); - } else if(escaped) { - buffer.append(currentChar); - escaped = false; - } else { - escaped = true; - } - } - - return buffer.toString(); - } - - /** - * A string that holds all the special chars. - */ - private static final String TSPECIALS = "()<>@,;:\\\"/[]?="; - -} --- /dev/null 2015-01-13 17:34:00.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/MimeTypeParameterList.java 2015-01-13 17:33:42.918668800 +0400 @@ -0,0 +1,404 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.awt.datatransfer; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + + +/** + * An object that encapsulates the parameter list of a MimeType + * as defined in RFC 2045 and 2046. + * + * @author jeff.dunn@eng.sun.com + */ +class MimeTypeParameterList implements Cloneable { + + /** + * Default constructor. + */ + public MimeTypeParameterList() { + parameters = new Hashtable<>(); + } + + public MimeTypeParameterList(String rawdata) + throws MimeTypeParseException + { + parameters = new Hashtable<>(); + + // now parse rawdata + parse(rawdata); + } + + public int hashCode() { + int code = Integer.MAX_VALUE/45; // "random" value for empty lists + String paramName = null; + Enumeration enum_ = this.getNames(); + + while (enum_.hasMoreElements()) { + paramName = enum_.nextElement(); + code += paramName.hashCode(); + code += this.get(paramName).hashCode(); + } + + return code; + } // hashCode() + + /** + * Two parameter lists are considered equal if they have exactly + * the same set of parameter names and associated values. The + * order of the parameters is not considered. + */ + public boolean equals(Object thatObject) { + //System.out.println("MimeTypeParameterList.equals("+this+","+thatObject+")"); + if (!(thatObject instanceof MimeTypeParameterList)) { + return false; + } + MimeTypeParameterList that = (MimeTypeParameterList)thatObject; + if (this.size() != that.size()) { + return false; + } + String name = null; + String thisValue = null; + String thatValue = null; + Set> entries = parameters.entrySet(); + Iterator> iterator = entries.iterator(); + Map.Entry entry = null; + while (iterator.hasNext()) { + entry = iterator.next(); + name = entry.getKey(); + thisValue = entry.getValue(); + thatValue = that.parameters.get(name); + if ((thisValue == null) || (thatValue == null)) { + // both null -> equal, only one null -> not equal + if (thisValue != thatValue) { + return false; + } + } else if (!thisValue.equals(thatValue)) { + return false; + } + } // while iterator + + return true; + } // equals() + + /** + * A routine for parsing the parameter list out of a String. + */ + protected void parse(String rawdata) throws MimeTypeParseException { + int length = rawdata.length(); + if(length > 0) { + int currentIndex = skipWhiteSpace(rawdata, 0); + int lastIndex = 0; + + if(currentIndex < length) { + char currentChar = rawdata.charAt(currentIndex); + while ((currentIndex < length) && (currentChar == ';')) { + String name; + String value; + boolean foundit; + + // eat the ';' + ++currentIndex; + + // now parse the parameter name + + // skip whitespace + currentIndex = skipWhiteSpace(rawdata, currentIndex); + + if(currentIndex < length) { + // find the end of the token char run + lastIndex = currentIndex; + currentChar = rawdata.charAt(currentIndex); + while((currentIndex < length) && isTokenChar(currentChar)) { + ++currentIndex; + currentChar = rawdata.charAt(currentIndex); + } + name = rawdata.substring(lastIndex, currentIndex).toLowerCase(); + + // now parse the '=' that separates the name from the value + + // skip whitespace + currentIndex = skipWhiteSpace(rawdata, currentIndex); + + if((currentIndex < length) && (rawdata.charAt(currentIndex) == '=')) { + // eat it and parse the parameter value + ++currentIndex; + + // skip whitespace + currentIndex = skipWhiteSpace(rawdata, currentIndex); + + if(currentIndex < length) { + // now find out whether or not we have a quoted value + currentChar = rawdata.charAt(currentIndex); + if(currentChar == '"') { + // yup it's quoted so eat it and capture the quoted string + ++currentIndex; + lastIndex = currentIndex; + + if(currentIndex < length) { + // find the next unescaped quote + foundit = false; + while((currentIndex < length) && !foundit) { + currentChar = rawdata.charAt(currentIndex); + if(currentChar == '\\') { + // found an escape sequence so pass this and the next character + currentIndex += 2; + } else if(currentChar == '"') { + // found it! + foundit = true; + } else { + ++currentIndex; + } + } + if(currentChar == '"') { + value = unquote(rawdata.substring(lastIndex, currentIndex)); + // eat the quote + ++currentIndex; + } else { + throw new MimeTypeParseException("Encountered unterminated quoted parameter value."); + } + } else { + throw new MimeTypeParseException("Encountered unterminated quoted parameter value."); + } + } else if(isTokenChar(currentChar)) { + // nope it's an ordinary token so it ends with a non-token char + lastIndex = currentIndex; + foundit = false; + while((currentIndex < length) && !foundit) { + currentChar = rawdata.charAt(currentIndex); + + if(isTokenChar(currentChar)) { + ++currentIndex; + } else { + foundit = true; + } + } + value = rawdata.substring(lastIndex, currentIndex); + } else { + // it ain't a value + throw new MimeTypeParseException("Unexpected character encountered at index " + currentIndex); + } + + // now put the data into the hashtable + parameters.put(name, value); + } else { + throw new MimeTypeParseException("Couldn't find a value for parameter named " + name); + } + } else { + throw new MimeTypeParseException("Couldn't find the '=' that separates a parameter name from its value."); + } + } else { + throw new MimeTypeParseException("Couldn't find parameter name"); + } + + // setup the next iteration + currentIndex = skipWhiteSpace(rawdata, currentIndex); + if(currentIndex < length) { + currentChar = rawdata.charAt(currentIndex); + } + } + if(currentIndex < length) { + throw new MimeTypeParseException("More characters encountered in input than expected."); + } + } + } + } + + /** + * return the number of name-value pairs in this list. + */ + public int size() { + return parameters.size(); + } + + /** + * Determine whether or not this list is empty. + */ + public boolean isEmpty() { + return parameters.isEmpty(); + } + + /** + * Retrieve the value associated with the given name, or null if there + * is no current association. + */ + public String get(String name) { + return parameters.get(name.trim().toLowerCase()); + } + + /** + * Set the value to be associated with the given name, replacing + * any previous association. + */ + public void set(String name, String value) { + parameters.put(name.trim().toLowerCase(), value); + } + + /** + * Remove any value associated with the given name. + */ + public void remove(String name) { + parameters.remove(name.trim().toLowerCase()); + } + + /** + * Retrieve an enumeration of all the names in this list. + */ + public Enumeration getNames() { + return parameters.keys(); + } + + public String toString() { + // Heuristic: 8 characters per field + StringBuilder buffer = new StringBuilder(parameters.size() * 16); + + Enumeration keys = parameters.keys(); + while(keys.hasMoreElements()) + { + buffer.append("; "); + + String key = keys.nextElement(); + buffer.append(key); + buffer.append('='); + buffer.append(quote(parameters.get(key))); + } + + return buffer.toString(); + } + + /** + * @return a clone of this object + */ + @SuppressWarnings("unchecked") // Cast from clone + public Object clone() { + MimeTypeParameterList newObj = null; + try { + newObj = (MimeTypeParameterList)super.clone(); + } catch (CloneNotSupportedException cannotHappen) { + } + newObj.parameters = (Hashtable)parameters.clone(); + return newObj; + } + + private Hashtable parameters; + + // below here be scary parsing related things + + /** + * Determine whether or not a given character belongs to a legal token. + */ + private static boolean isTokenChar(char c) { + return ((c > 040) && (c < 0177)) && (TSPECIALS.indexOf(c) < 0); + } + + /** + * return the index of the first non white space character in + * rawdata at or after index i. + */ + private static int skipWhiteSpace(String rawdata, int i) { + int length = rawdata.length(); + if (i < length) { + char c = rawdata.charAt(i); + while ((i < length) && Character.isWhitespace(c)) { + ++i; + c = rawdata.charAt(i); + } + } + + return i; + } + + /** + * A routine that knows how and when to quote and escape the given value. + */ + private static String quote(String value) { + boolean needsQuotes = false; + + // check to see if we actually have to quote this thing + int length = value.length(); + for(int i = 0; (i < length) && !needsQuotes; ++i) { + needsQuotes = !isTokenChar(value.charAt(i)); + } + + if(needsQuotes) { + StringBuilder buffer = new StringBuilder((int)(length * 1.5)); + + // add the initial quote + buffer.append('"'); + + // add the properly escaped text + for(int i = 0; i < length; ++i) { + char c = value.charAt(i); + if((c == '\\') || (c == '"')) { + buffer.append('\\'); + } + buffer.append(c); + } + + // add the closing quote + buffer.append('"'); + + return buffer.toString(); + } + else + { + return value; + } + } + + /** + * A routine that knows how to strip the quotes and escape sequences from the given value. + */ + private static String unquote(String value) { + int valueLength = value.length(); + StringBuilder buffer = new StringBuilder(valueLength); + + boolean escaped = false; + for(int i = 0; i < valueLength; ++i) { + char currentChar = value.charAt(i); + if(!escaped && (currentChar != '\\')) { + buffer.append(currentChar); + } else if(escaped) { + buffer.append(currentChar); + escaped = false; + } else { + escaped = true; + } + } + + return buffer.toString(); + } + + /** + * A string that holds all the special chars. + */ + private static final String TSPECIALS = "()<>@,;:\\\"/[]?="; + +} --- old/src/java.desktop/share/classes/java/awt/datatransfer/MimeTypeParseException.java 2015-01-13 17:34:12.339351600 +0400 +++ /dev/null 2015-01-13 17:34:12.000000000 +0400 @@ -1,55 +0,0 @@ -/* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.awt.datatransfer; - - -/** - * A class to encapsulate MimeType parsing related exceptions - * - * @serial exclude - * @since 1.3 - */ -public class MimeTypeParseException extends Exception { - - // use serialVersionUID from JDK 1.2.2 for interoperability - private static final long serialVersionUID = -5604407764691570741L; - - /** - * Constructs a MimeTypeParseException with no specified detail message. - */ - public MimeTypeParseException() { - super(); - } - - /** - * Constructs a MimeTypeParseException with the specified detail message. - * - * @param s the detail message. - */ - public MimeTypeParseException(String s) { - super(s); - } -} // class MimeTypeParseException --- /dev/null 2015-01-13 17:34:13.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/MimeTypeParseException.java 2015-01-13 17:34:11.857324000 +0400 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.awt.datatransfer; + + +/** + * A class to encapsulate MimeType parsing related exceptions + * + * @serial exclude + * @since 1.3 + */ +public class MimeTypeParseException extends Exception { + + // use serialVersionUID from JDK 1.2.2 for interoperability + private static final long serialVersionUID = -5604407764691570741L; + + /** + * Constructs a MimeTypeParseException with no specified detail message. + */ + public MimeTypeParseException() { + super(); + } + + /** + * Constructs a MimeTypeParseException with the specified detail message. + * + * @param s the detail message. + */ + public MimeTypeParseException(String s) { + super(s); + } +} // class MimeTypeParseException --- old/src/java.desktop/share/classes/java/awt/datatransfer/StringSelection.java 2015-01-13 17:34:17.164627600 +0400 +++ /dev/null 2015-01-13 17:34:17.000000000 +0400 @@ -1,143 +0,0 @@ -/* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.awt.datatransfer; - -import java.io.*; - - -/** - * A Transferable which implements the capability required - * to transfer a String. - * - * This Transferable properly supports - * DataFlavor.stringFlavor - * and all equivalent flavors. Support for - * DataFlavor.plainTextFlavor - * and all equivalent flavors is deprecated. No other - * DataFlavors are supported. - * - * @see java.awt.datatransfer.DataFlavor#stringFlavor - * @see java.awt.datatransfer.DataFlavor#plainTextFlavor - */ -public class StringSelection implements Transferable, ClipboardOwner { - - private static final int STRING = 0; - private static final int PLAIN_TEXT = 1; - - @SuppressWarnings("deprecation") - private static final DataFlavor[] flavors = { - DataFlavor.stringFlavor, - DataFlavor.plainTextFlavor // deprecated - }; - - private String data; - - /** - * Creates a Transferable capable of transferring - * the specified String. - * @param data the string to be transferred - */ - public StringSelection(String data) { - this.data = data; - } - - /** - * Returns an array of flavors in which this Transferable - * can provide the data. DataFlavor.stringFlavor - * is properly supported. - * Support for DataFlavor.plainTextFlavor is - * deprecated. - * - * @return an array of length two, whose elements are DataFlavor. - * stringFlavor and DataFlavor.plainTextFlavor - */ - public DataFlavor[] getTransferDataFlavors() { - // returning flavors itself would allow client code to modify - // our internal behavior - return flavors.clone(); - } - - /** - * Returns whether the requested flavor is supported by this - * Transferable. - * - * @param flavor the requested flavor for the data - * @return true if flavor is equal to - * DataFlavor.stringFlavor or - * DataFlavor.plainTextFlavor; false if flavor - * is not one of the above flavors - * @throws NullPointerException if flavor is null - */ - public boolean isDataFlavorSupported(DataFlavor flavor) { - // JCK Test StringSelection0003: if 'flavor' is null, throw NPE - for (int i = 0; i < flavors.length; i++) { - if (flavor.equals(flavors[i])) { - return true; - } - } - return false; - } - - /** - * Returns the Transferable's data in the requested - * DataFlavor if possible. If the desired flavor is - * DataFlavor.stringFlavor, or an equivalent flavor, - * the String representing the selection is - * returned. If the desired flavor is - * DataFlavor.plainTextFlavor, - * or an equivalent flavor, a Reader is returned. - * Note: The behavior of this method for - * DataFlavor.plainTextFlavor - * and equivalent DataFlavors is inconsistent with the - * definition of DataFlavor.plainTextFlavor. - * - * @param flavor the requested flavor for the data - * @return the data in the requested flavor, as outlined above - * @throws UnsupportedFlavorException if the requested data flavor is - * not equivalent to either DataFlavor.stringFlavor - * or DataFlavor.plainTextFlavor - * @throws IOException if an IOException occurs while retrieving the data. - * By default, StringSelection never throws this exception, but a - * subclass may. - * @throws NullPointerException if flavor is null - * @see java.io.Reader - */ - public Object getTransferData(DataFlavor flavor) - throws UnsupportedFlavorException, IOException - { - // JCK Test StringSelection0007: if 'flavor' is null, throw NPE - if (flavor.equals(flavors[STRING])) { - return (Object)data; - } else if (flavor.equals(flavors[PLAIN_TEXT])) { - return new StringReader(data == null ? "" : data); - } else { - throw new UnsupportedFlavorException(flavor); - } - } - - public void lostOwnership(Clipboard clipboard, Transferable contents) { - } -} --- /dev/null 2015-01-13 17:34:17.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/StringSelection.java 2015-01-13 17:34:16.421585100 +0400 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.awt.datatransfer; + +import java.io.*; + + +/** + * A Transferable which implements the capability required + * to transfer a String. + * + * This Transferable properly supports + * DataFlavor.stringFlavor + * and all equivalent flavors. Support for + * DataFlavor.plainTextFlavor + * and all equivalent flavors is deprecated. No other + * DataFlavors are supported. + * + * @see java.awt.datatransfer.DataFlavor#stringFlavor + * @see java.awt.datatransfer.DataFlavor#plainTextFlavor + */ +public class StringSelection implements Transferable, ClipboardOwner { + + private static final int STRING = 0; + private static final int PLAIN_TEXT = 1; + + @SuppressWarnings("deprecation") + private static final DataFlavor[] flavors = { + DataFlavor.stringFlavor, + DataFlavor.plainTextFlavor // deprecated + }; + + private String data; + + /** + * Creates a Transferable capable of transferring + * the specified String. + * @param data the string to be transferred + */ + public StringSelection(String data) { + this.data = data; + } + + /** + * Returns an array of flavors in which this Transferable + * can provide the data. DataFlavor.stringFlavor + * is properly supported. + * Support for DataFlavor.plainTextFlavor is + * deprecated. + * + * @return an array of length two, whose elements are DataFlavor. + * stringFlavor and DataFlavor.plainTextFlavor + */ + public DataFlavor[] getTransferDataFlavors() { + // returning flavors itself would allow client code to modify + // our internal behavior + return flavors.clone(); + } + + /** + * Returns whether the requested flavor is supported by this + * Transferable. + * + * @param flavor the requested flavor for the data + * @return true if flavor is equal to + * DataFlavor.stringFlavor or + * DataFlavor.plainTextFlavor; false if flavor + * is not one of the above flavors + * @throws NullPointerException if flavor is null + */ + public boolean isDataFlavorSupported(DataFlavor flavor) { + // JCK Test StringSelection0003: if 'flavor' is null, throw NPE + for (int i = 0; i < flavors.length; i++) { + if (flavor.equals(flavors[i])) { + return true; + } + } + return false; + } + + /** + * Returns the Transferable's data in the requested + * DataFlavor if possible. If the desired flavor is + * DataFlavor.stringFlavor, or an equivalent flavor, + * the String representing the selection is + * returned. If the desired flavor is + * DataFlavor.plainTextFlavor, + * or an equivalent flavor, a Reader is returned. + * Note: The behavior of this method for + * DataFlavor.plainTextFlavor + * and equivalent DataFlavors is inconsistent with the + * definition of DataFlavor.plainTextFlavor. + * + * @param flavor the requested flavor for the data + * @return the data in the requested flavor, as outlined above + * @throws UnsupportedFlavorException if the requested data flavor is + * not equivalent to either DataFlavor.stringFlavor + * or DataFlavor.plainTextFlavor + * @throws IOException if an IOException occurs while retrieving the data. + * By default, StringSelection never throws this exception, but a + * subclass may. + * @throws NullPointerException if flavor is null + * @see java.io.Reader + */ + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException + { + // JCK Test StringSelection0007: if 'flavor' is null, throw NPE + if (flavor.equals(flavors[STRING])) { + return (Object)data; + } else if (flavor.equals(flavors[PLAIN_TEXT])) { + return new StringReader(data == null ? "" : data); + } else { + throw new UnsupportedFlavorException(flavor); + } + } + + public void lostOwnership(Clipboard clipboard, Transferable contents) { + } +} --- old/src/java.desktop/share/classes/java/awt/datatransfer/SystemFlavorMap.java 2015-01-13 17:34:25.351095800 +0400 +++ /dev/null 2015-01-13 17:34:32.000000000 +0400 @@ -1,1094 +0,0 @@ -/* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.awt.datatransfer; - -import sun.datatransfer.DataFlavorUtil; -import sun.datatransfer.DesktopDatatransferService; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.ref.SoftReference; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -/** - * The SystemFlavorMap is a configurable map between "natives" (Strings), which - * correspond to platform-specific data formats, and "flavors" (DataFlavors), - * which correspond to platform-independent MIME types. This mapping is used - * by the data transfer subsystem to transfer data between Java and native - * applications, and between Java applications in separate VMs. - * - * @since 1.2 - */ -public final class SystemFlavorMap implements FlavorMap, FlavorTable { - - /** - * Constant prefix used to tag Java types converted to native platform - * type. - */ - private static String JavaMIME = "JAVA_DATAFLAVOR:"; - - private static final Object FLAVOR_MAP_KEY = new Object(); - - /** - * The list of valid, decoded text flavor representation classes, in order - * from best to worst. - */ - private static final String[] UNICODE_TEXT_CLASSES = { - "java.io.Reader", "java.lang.String", "java.nio.CharBuffer", "\"[C\"" - }; - - /** - * The list of valid, encoded text flavor representation classes, in order - * from best to worst. - */ - private static final String[] ENCODED_TEXT_CLASSES = { - "java.io.InputStream", "java.nio.ByteBuffer", "\"[B\"" - }; - - /** - * A String representing text/plain MIME type. - */ - private static final String TEXT_PLAIN_BASE_TYPE = "text/plain"; - - /** - * A String representing text/html MIME type. - */ - private static final String HTML_TEXT_BASE_TYPE = "text/html"; - - /** - * Maps native Strings to Lists of DataFlavors (or base type Strings for - * text DataFlavors). - * Do not use the field directly, use getNativeToFlavor() instead. - */ - private final Map> nativeToFlavor = new HashMap<>(); - - /** - * Accessor to nativeToFlavor map. Since we use lazy initialization we must - * use this accessor instead of direct access to the field which may not be - * initialized yet. This method will initialize the field if needed. - * - * @return nativeToFlavor - */ - private Map> getNativeToFlavor() { - if (!isMapInitialized) { - initSystemFlavorMap(); - } - return nativeToFlavor; - } - - /** - * Maps DataFlavors (or base type Strings for text DataFlavors) to Lists of - * native Strings. - * Do not use the field directly, use getFlavorToNative() instead. - */ - private final Map> flavorToNative = new HashMap<>(); - - /** - * Accessor to flavorToNative map. Since we use lazy initialization we must - * use this accessor instead of direct access to the field which may not be - * initialized yet. This method will initialize the field if needed. - * - * @return flavorToNative - */ - private synchronized Map> getFlavorToNative() { - if (!isMapInitialized) { - initSystemFlavorMap(); - } - return flavorToNative; - } - - /** - * Maps a text DataFlavor primary mime-type to the native. Used only to store - * standard mappings registered in the flavormap.properties - * Do not use this field directly, use getTextTypeToNative() instead. - */ - private Map> textTypeToNative = new HashMap<>(); - - /** - * Shows if the object has been initialized. - */ - private boolean isMapInitialized = false; - - /** - * An accessor to textTypeToNative map. Since we use lazy initialization we - * must use this accessor instead of direct access to the field which may not - * be initialized yet. This method will initialize the field if needed. - * - * @return textTypeToNative - */ - private synchronized Map> getTextTypeToNative() { - if (!isMapInitialized) { - initSystemFlavorMap(); - // From this point the map should not be modified - textTypeToNative = Collections.unmodifiableMap(textTypeToNative); - } - return textTypeToNative; - } - - /** - * Caches the result of getNativesForFlavor(). Maps DataFlavors to - * SoftReferences which reference LinkedHashSet of String natives. - */ - private final SoftCache nativesForFlavorCache = new SoftCache<>(); - - /** - * Caches the result getFlavorsForNative(). Maps String natives to - * SoftReferences which reference LinkedHashSet of DataFlavors. - */ - private final SoftCache flavorsForNativeCache = new SoftCache<>(); - - /** - * Dynamic mapping generation used for text mappings should not be applied - * to the DataFlavors and String natives for which the mappings have been - * explicitly specified with setFlavorsForNative() or - * setNativesForFlavor(). This keeps all such keys. - */ - private Set disabledMappingGenerationKeys = new HashSet<>(); - - /** - * Returns the default FlavorMap for this thread's ClassLoader. - * - * @return the default FlavorMap for this thread's ClassLoader - */ - public static FlavorMap getDefaultFlavorMap() { - return DataFlavorUtil.getDesktopService().getFlavorMap(SystemFlavorMap::new); - } - - private SystemFlavorMap() { - } - - /** - * Initializes a SystemFlavorMap by reading flavormap.properties - * For thread-safety must be called under lock on this. - */ - private void initSystemFlavorMap() { - if (isMapInitialized) { - return; - } - isMapInitialized = true; - - InputStream is = SystemFlavorMap.class.getResourceAsStream("/sun/datatransfer/resources/flavormap.properties"); - if (is == null) { - throw new InternalError("Default flavor mapping not found"); - } - - try (InputStreamReader isr = new InputStreamReader(is); - BufferedReader reader = new BufferedReader(isr)) { - String line; - while ((line = reader.readLine()) != null) { - line = line.trim(); - if (line.startsWith("#") || line.isEmpty()) continue; - while (line.endsWith("\\")) { - line = line.substring(0, line.length() - 1) + reader.readLine().trim(); - } - int delimiterPosition = line.indexOf('='); - String key = line.substring(0, delimiterPosition).replaceAll("\\ ", " "); - String[] values = line.substring(delimiterPosition + 1, line.length()).split(","); - for (String value : values) { - try { - value = loadConvert(value); - MimeType mime = new MimeType(value); - if ("text".equals(mime.getPrimaryType())) { - String charset = mime.getParameter("charset"); - if (DataFlavorUtil.doesSubtypeSupportCharset(mime.getSubType(), charset)) - { - // We need to store the charset and eoln - // parameters, if any, so that the - // DataTransferer will have this information - // for conversion into the native format. - DesktopDatatransferService desktopService = - DataFlavorUtil.getDesktopService(); - if (desktopService.isDesktopPresent()) { - desktopService.registerTextFlavorProperties( - key, charset, - mime.getParameter("eoln"), - mime.getParameter("terminators")); - } - } - - // But don't store any of these parameters in the - // DataFlavor itself for any text natives (even - // non-charset ones). The SystemFlavorMap will - // synthesize the appropriate mappings later. - mime.removeParameter("charset"); - mime.removeParameter("class"); - mime.removeParameter("eoln"); - mime.removeParameter("terminators"); - value = mime.toString(); - } - } catch (MimeTypeParseException e) { - e.printStackTrace(); - continue; - } - - DataFlavor flavor; - try { - flavor = new DataFlavor(value); - } catch (Exception e) { - try { - flavor = new DataFlavor(value, null); - } catch (Exception ee) { - ee.printStackTrace(); - continue; - } - } - - final LinkedHashSet dfs = new LinkedHashSet<>(); - dfs.add(flavor); - - if ("text".equals(flavor.getPrimaryType())) { - dfs.addAll(convertMimeTypeToDataFlavors(value)); - store(flavor.mimeType.getBaseType(), key, getTextTypeToNative()); - } - - for (DataFlavor df : dfs) { - store(df, key, getFlavorToNative()); - store(key, df, getNativeToFlavor()); - } - } - } - } catch (IOException e) { - throw new InternalError("Error reading default flavor mapping", e); - } - } - - // Copied from java.util.Properties - private static String loadConvert(String theString) { - char aChar; - int len = theString.length(); - StringBuilder outBuffer = new StringBuilder(len); - - for (int x = 0; x < len; ) { - aChar = theString.charAt(x++); - if (aChar == '\\') { - aChar = theString.charAt(x++); - if (aChar == 'u') { - // Read the xxxx - int value = 0; - for (int i = 0; i < 4; i++) { - aChar = theString.charAt(x++); - switch (aChar) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': { - value = (value << 4) + aChar - '0'; - break; - } - case 'a': case 'b': case 'c': - case 'd': case 'e': case 'f': { - value = (value << 4) + 10 + aChar - 'a'; - break; - } - case 'A': case 'B': case 'C': - case 'D': case 'E': case 'F': { - value = (value << 4) + 10 + aChar - 'A'; - break; - } - default: { - throw new IllegalArgumentException( - "Malformed \\uxxxx encoding."); - } - } - } - outBuffer.append((char)value); - } else { - if (aChar == 't') { - aChar = '\t'; - } else if (aChar == 'r') { - aChar = '\r'; - } else if (aChar == 'n') { - aChar = '\n'; - } else if (aChar == 'f') { - aChar = '\f'; - } - outBuffer.append(aChar); - } - } else { - outBuffer.append(aChar); - } - } - return outBuffer.toString(); - } - - /** - * Stores the listed object under the specified hash key in map. Unlike a - * standard map, the listed object will not replace any object already at - * the appropriate Map location, but rather will be appended to a List - * stored in that location. - */ - private void store(H hashed, L listed, Map> map) { - LinkedHashSet list = map.get(hashed); - if (list == null) { - list = new LinkedHashSet<>(1); - map.put(hashed, list); - } - if (!list.contains(listed)) { - list.add(listed); - } - } - - /** - * Semantically equivalent to 'nativeToFlavor.get(nat)'. This method - * handles the case where 'nat' is not found in 'nativeToFlavor'. In that - * case, a new DataFlavor is synthesized, stored, and returned, if and - * only if the specified native is encoded as a Java MIME type. - */ - private LinkedHashSet nativeToFlavorLookup(String nat) { - LinkedHashSet flavors = getNativeToFlavor().get(nat); - - if (nat != null && !disabledMappingGenerationKeys.contains(nat)) { - DesktopDatatransferService desktopService = DataFlavorUtil.getDesktopService(); - if (desktopService.isDesktopPresent()) { - LinkedHashSet platformFlavors = - desktopService.getPlatformMappingsForNative(nat); - if (!platformFlavors.isEmpty()) { - if (flavors != null) { - // Prepending the platform-specific mappings ensures - // that the flavors added with - // addFlavorForUnencodedNative() are at the end of - // list. - platformFlavors.addAll(flavors); - } - flavors = platformFlavors; - } - } - } - - if (flavors == null && isJavaMIMEType(nat)) { - String decoded = decodeJavaMIMEType(nat); - DataFlavor flavor = null; - - try { - flavor = new DataFlavor(decoded); - } catch (Exception e) { - System.err.println("Exception \"" + e.getClass().getName() + - ": " + e.getMessage() + - "\"while constructing DataFlavor for: " + - decoded); - } - - if (flavor != null) { - flavors = new LinkedHashSet<>(1); - getNativeToFlavor().put(nat, flavors); - flavors.add(flavor); - flavorsForNativeCache.remove(nat); - - LinkedHashSet natives = getFlavorToNative().get(flavor); - if (natives == null) { - natives = new LinkedHashSet<>(1); - getFlavorToNative().put(flavor, natives); - } - natives.add(nat); - nativesForFlavorCache.remove(flavor); - } - } - - return (flavors != null) ? flavors : new LinkedHashSet<>(0); - } - - /** - * Semantically equivalent to 'flavorToNative.get(flav)'. This method - * handles the case where 'flav' is not found in 'flavorToNative' depending - * on the value of passes 'synthesize' parameter. If 'synthesize' is - * SYNTHESIZE_IF_NOT_FOUND a native is synthesized, stored, and returned by - * encoding the DataFlavor's MIME type. Otherwise an empty List is returned - * and 'flavorToNative' remains unaffected. - */ - private LinkedHashSet flavorToNativeLookup(final DataFlavor flav, - final boolean synthesize) { - - LinkedHashSet natives = getFlavorToNative().get(flav); - - if (flav != null && !disabledMappingGenerationKeys.contains(flav)) { - DesktopDatatransferService desktopService = DataFlavorUtil.getDesktopService(); - if (desktopService.isDesktopPresent()) { - LinkedHashSet platformNatives = - desktopService.getPlatformMappingsForFlavor(flav); - if (!platformNatives.isEmpty()) { - if (natives != null) { - // Prepend the platform-specific mappings to ensure - // that the natives added with - // addUnencodedNativeForFlavor() are at the end of - // list. - platformNatives.addAll(natives); - } - natives = platformNatives; - } - } - } - - if (natives == null) { - if (synthesize) { - String encoded = encodeDataFlavor(flav); - natives = new LinkedHashSet<>(1); - getFlavorToNative().put(flav, natives); - natives.add(encoded); - - LinkedHashSet flavors = getNativeToFlavor().get(encoded); - if (flavors == null) { - flavors = new LinkedHashSet<>(1); - getNativeToFlavor().put(encoded, flavors); - } - flavors.add(flav); - - nativesForFlavorCache.remove(flav); - flavorsForNativeCache.remove(encoded); - } else { - natives = new LinkedHashSet<>(0); - } - } - - return new LinkedHashSet<>(natives); - } - - /** - * Returns a List of String natives to which the - * specified DataFlavor can be translated by the data transfer - * subsystem. The List will be sorted from best native to - * worst. That is, the first native will best reflect data in the specified - * flavor to the underlying native platform. - *

- * If the specified DataFlavor is previously unknown to the - * data transfer subsystem and the data transfer subsystem is unable to - * translate this DataFlavor to any existing native, then - * invoking this method will establish a - * mapping in both directions between the specified DataFlavor - * and an encoded version of its MIME type as its native. - * - * @param flav the DataFlavor whose corresponding natives - * should be returned. If null is specified, all - * natives currently known to the data transfer subsystem are - * returned in a non-deterministic order. - * @return a java.util.List of java.lang.String - * objects which are platform-specific representations of platform- - * specific data formats - * - * @see #encodeDataFlavor - * @since 1.4 - */ - @Override - public synchronized List getNativesForFlavor(DataFlavor flav) { - LinkedHashSet retval = nativesForFlavorCache.check(flav); - if (retval != null) { - return new ArrayList<>(retval); - } - - if (flav == null) { - retval = new LinkedHashSet<>(getNativeToFlavor().keySet()); - } else if (disabledMappingGenerationKeys.contains(flav)) { - // In this case we shouldn't synthesize a native for this flavor, - // since its mappings were explicitly specified. - retval = flavorToNativeLookup(flav, false); - } else if (DataFlavorUtil.isFlavorCharsetTextType(flav)) { - retval = new LinkedHashSet<>(0); - - // For text/* flavors, flavor-to-native mappings specified in - // flavormap.properties are stored per flavor's base type. - if ("text".equals(flav.getPrimaryType())) { - LinkedHashSet textTypeNatives = - getTextTypeToNative().get(flav.mimeType.getBaseType()); - if (textTypeNatives != null) { - retval.addAll(textTypeNatives); - } - } - - // Also include text/plain natives, but don't duplicate Strings - LinkedHashSet textTypeNatives = - getTextTypeToNative().get(TEXT_PLAIN_BASE_TYPE); - if (textTypeNatives != null) { - retval.addAll(textTypeNatives); - } - - if (retval.isEmpty()) { - retval = flavorToNativeLookup(flav, true); - } else { - // In this branch it is guaranteed that natives explicitly - // listed for flav's MIME type were added with - // addUnencodedNativeForFlavor(), so they have lower priority. - retval.addAll(flavorToNativeLookup(flav, false)); - } - } else if (DataFlavorUtil.isFlavorNoncharsetTextType(flav)) { - retval = getTextTypeToNative().get(flav.mimeType.getBaseType()); - - if (retval == null || retval.isEmpty()) { - retval = flavorToNativeLookup(flav, true); - } else { - // In this branch it is guaranteed that natives explicitly - // listed for flav's MIME type were added with - // addUnencodedNativeForFlavor(), so they have lower priority. - retval.addAll(flavorToNativeLookup(flav, false)); - } - } else { - retval = flavorToNativeLookup(flav, true); - } - - nativesForFlavorCache.put(flav, retval); - // Create a copy, because client code can modify the returned list. - return new ArrayList<>(retval); - } - - /** - * Returns a List of DataFlavors to which the - * specified String native can be translated by the data - * transfer subsystem. The List will be sorted from best - * DataFlavor to worst. That is, the first - * DataFlavor will best reflect data in the specified - * native to a Java application. - *

- * If the specified native is previously unknown to the data transfer - * subsystem, and that native has been properly encoded, then invoking this - * method will establish a mapping in both directions between the specified - * native and a DataFlavor whose MIME type is a decoded - * version of the native. - *

- * If the specified native is not a properly encoded native and the - * mappings for this native have not been altered with - * setFlavorsForNative, then the contents of the - * List is platform dependent, but null - * cannot be returned. - * - * @param nat the native whose corresponding DataFlavors - * should be returned. If null is specified, all - * DataFlavors currently known to the data transfer - * subsystem are returned in a non-deterministic order. - * @return a java.util.List of DataFlavor - * objects into which platform-specific data in the specified, - * platform-specific native can be translated - * - * @see #encodeJavaMIMEType - * @since 1.4 - */ - @Override - public synchronized List getFlavorsForNative(String nat) { - LinkedHashSet returnValue = flavorsForNativeCache.check(nat); - if (returnValue != null) { - return new ArrayList<>(returnValue); - } else { - returnValue = new LinkedHashSet<>(); - } - - if (nat == null) { - for (String n : getNativesForFlavor(null)) { - returnValue.addAll(getFlavorsForNative(n)); - } - } else { - final LinkedHashSet flavors = nativeToFlavorLookup(nat); - if (disabledMappingGenerationKeys.contains(nat)) { - return new ArrayList<>(flavors); - } - - final LinkedHashSet flavorsWithSynthesized = - nativeToFlavorLookup(nat); - - for (DataFlavor df : flavorsWithSynthesized) { - returnValue.add(df); - if ("text".equals(df.getPrimaryType())) { - String baseType = df.mimeType.getBaseType(); - returnValue.addAll(convertMimeTypeToDataFlavors(baseType)); - } - } - } - flavorsForNativeCache.put(nat, returnValue); - return new ArrayList<>(returnValue); - } - - @SuppressWarnings("deprecation") - private static Set convertMimeTypeToDataFlavors( - final String baseType) { - - final Set returnValue = new LinkedHashSet<>(); - - String subType = null; - - try { - final MimeType mimeType = new MimeType(baseType); - subType = mimeType.getSubType(); - } catch (MimeTypeParseException mtpe) { - // Cannot happen, since we checked all mappings - // on load from flavormap.properties. - } - - if (DataFlavorUtil.doesSubtypeSupportCharset(subType, null)) { - if (TEXT_PLAIN_BASE_TYPE.equals(baseType)) - { - returnValue.add(DataFlavor.stringFlavor); - } - - for (String unicodeClassName : UNICODE_TEXT_CLASSES) { - final String mimeType = baseType + ";charset=Unicode;class=" + - unicodeClassName; - - final LinkedHashSet mimeTypes = - handleHtmlMimeTypes(baseType, mimeType); - for (String mt : mimeTypes) { - DataFlavor toAdd = null; - try { - toAdd = new DataFlavor(mt); - } catch (ClassNotFoundException cannotHappen) { - } - returnValue.add(toAdd); - } - } - - for (String charset : DataFlavorUtil.standardEncodings()) { - - for (String encodedTextClass : ENCODED_TEXT_CLASSES) { - final String mimeType = - baseType + ";charset=" + charset + - ";class=" + encodedTextClass; - - final LinkedHashSet mimeTypes = - handleHtmlMimeTypes(baseType, mimeType); - - for (String mt : mimeTypes) { - - DataFlavor df = null; - - try { - df = new DataFlavor(mt); - // Check for equality to plainTextFlavor so - // that we can ensure that the exact charset of - // plainTextFlavor, not the canonical charset - // or another equivalent charset with a - // different name, is used. - if (df.equals(DataFlavor.plainTextFlavor)) { - df = DataFlavor.plainTextFlavor; - } - } catch (ClassNotFoundException cannotHappen) { - } - - returnValue.add(df); - } - } - } - - if (TEXT_PLAIN_BASE_TYPE.equals(baseType)) - { - returnValue.add(DataFlavor.plainTextFlavor); - } - } else { - // Non-charset text natives should be treated as - // opaque, 8-bit data in any of its various - // representations. - for (String encodedTextClassName : ENCODED_TEXT_CLASSES) { - DataFlavor toAdd = null; - try { - toAdd = new DataFlavor(baseType + - ";class=" + encodedTextClassName); - } catch (ClassNotFoundException cannotHappen) { - } - returnValue.add(toAdd); - } - } - return returnValue; - } - - private static final String [] htmlDocumentTypes = - new String [] {"all", "selection", "fragment"}; - - private static LinkedHashSet handleHtmlMimeTypes(String baseType, - String mimeType) { - - LinkedHashSet returnValues = new LinkedHashSet<>(); - - if (HTML_TEXT_BASE_TYPE.equals(baseType)) { - for (String documentType : htmlDocumentTypes) { - returnValues.add(mimeType + ";document=" + documentType); - } - } else { - returnValues.add(mimeType); - } - - return returnValues; - } - - /** - * Returns a Map of the specified DataFlavors to - * their most preferred String native. Each native value will - * be the same as the first native in the List returned by - * getNativesForFlavor for the specified flavor. - *

- * If a specified DataFlavor is previously unknown to the - * data transfer subsystem, then invoking this method will establish a - * mapping in both directions between the specified DataFlavor - * and an encoded version of its MIME type as its native. - * - * @param flavors an array of DataFlavors which will be the - * key set of the returned Map. If null is - * specified, a mapping of all DataFlavors known to the - * data transfer subsystem to their most preferred - * String natives will be returned. - * @return a java.util.Map of DataFlavors to - * String natives - * - * @see #getNativesForFlavor - * @see #encodeDataFlavor - */ - @Override - public synchronized Map getNativesForFlavors(DataFlavor[] flavors) - { - // Use getNativesForFlavor to generate extra natives for text flavors - // and stringFlavor - - if (flavors == null) { - List flavor_list = getFlavorsForNative(null); - flavors = new DataFlavor[flavor_list.size()]; - flavor_list.toArray(flavors); - } - - Map retval = new HashMap<>(flavors.length, 1.0f); - for (DataFlavor flavor : flavors) { - List natives = getNativesForFlavor(flavor); - String nat = (natives.isEmpty()) ? null : natives.get(0); - retval.put(flavor, nat); - } - - return retval; - } - - /** - * Returns a Map of the specified String natives - * to their most preferred DataFlavor. Each - * DataFlavor value will be the same as the first - * DataFlavor in the List returned by - * getFlavorsForNative for the specified native. - *

- * If a specified native is previously unknown to the data transfer - * subsystem, and that native has been properly encoded, then invoking this - * method will establish a mapping in both directions between the specified - * native and a DataFlavor whose MIME type is a decoded - * version of the native. - * - * @param natives an array of Strings which will be the - * key set of the returned Map. If null is - * specified, a mapping of all supported String natives - * to their most preferred DataFlavors will be - * returned. - * @return a java.util.Map of String natives to - * DataFlavors - * - * @see #getFlavorsForNative - * @see #encodeJavaMIMEType - */ - @Override - public synchronized Map getFlavorsForNatives(String[] natives) - { - // Use getFlavorsForNative to generate extra flavors for text natives - if (natives == null) { - List nativesList = getNativesForFlavor(null); - natives = new String[nativesList.size()]; - nativesList.toArray(natives); - } - - Map retval = new HashMap<>(natives.length, 1.0f); - for (String aNative : natives) { - List flavors = getFlavorsForNative(aNative); - DataFlavor flav = (flavors.isEmpty())? null : flavors.get(0); - retval.put(aNative, flav); - } - return retval; - } - - /** - * Adds a mapping from the specified DataFlavor (and all - * DataFlavors equal to the specified DataFlavor) - * to the specified String native. - * Unlike getNativesForFlavor, the mapping will only be - * established in one direction, and the native will not be encoded. To - * establish a two-way mapping, call - * addFlavorForUnencodedNative as well. The new mapping will - * be of lower priority than any existing mapping. - * This method has no effect if a mapping from the specified or equal - * DataFlavor to the specified String native - * already exists. - * - * @param flav the DataFlavor key for the mapping - * @param nat the String native value for the mapping - * @throws NullPointerException if flav or nat is null - * - * @see #addFlavorForUnencodedNative - * @since 1.4 - */ - public synchronized void addUnencodedNativeForFlavor(DataFlavor flav, - String nat) { - Objects.requireNonNull(nat, "Null native not permitted"); - Objects.requireNonNull(flav, "Null flavor not permitted"); - - LinkedHashSet natives = getFlavorToNative().get(flav); - if (natives == null) { - natives = new LinkedHashSet<>(1); - getFlavorToNative().put(flav, natives); - } - natives.add(nat); - nativesForFlavorCache.remove(flav); - } - - /** - * Discards the current mappings for the specified DataFlavor - * and all DataFlavors equal to the specified - * DataFlavor, and creates new mappings to the - * specified String natives. - * Unlike getNativesForFlavor, the mappings will only be - * established in one direction, and the natives will not be encoded. To - * establish two-way mappings, call setFlavorsForNative - * as well. The first native in the array will represent the highest - * priority mapping. Subsequent natives will represent mappings of - * decreasing priority. - *

- * If the array contains several elements that reference equal - * String natives, this method will establish new mappings - * for the first of those elements and ignore the rest of them. - *

- * It is recommended that client code not reset mappings established by the - * data transfer subsystem. This method should only be used for - * application-level mappings. - * - * @param flav the DataFlavor key for the mappings - * @param natives the String native values for the mappings - * @throws NullPointerException if flav or natives is null - * or if natives contains null elements - * - * @see #setFlavorsForNative - * @since 1.4 - */ - public synchronized void setNativesForFlavor(DataFlavor flav, - String[] natives) { - Objects.requireNonNull(natives, "Null natives not permitted"); - Objects.requireNonNull(flav, "Null flavors not permitted"); - - getFlavorToNative().remove(flav); - for (String aNative : natives) { - addUnencodedNativeForFlavor(flav, aNative); - } - disabledMappingGenerationKeys.add(flav); - nativesForFlavorCache.remove(flav); - } - - /** - * Adds a mapping from a single String native to a single - * DataFlavor. Unlike getFlavorsForNative, the - * mapping will only be established in one direction, and the native will - * not be encoded. To establish a two-way mapping, call - * addUnencodedNativeForFlavor as well. The new mapping will - * be of lower priority than any existing mapping. - * This method has no effect if a mapping from the specified - * String native to the specified or equal - * DataFlavor already exists. - * - * @param nat the String native key for the mapping - * @param flav the DataFlavor value for the mapping - * @throws NullPointerException if nat or flav is null - * - * @see #addUnencodedNativeForFlavor - * @since 1.4 - */ - public synchronized void addFlavorForUnencodedNative(String nat, - DataFlavor flav) { - Objects.requireNonNull(nat, "Null native not permitted"); - Objects.requireNonNull(flav, "Null flavor not permitted"); - - LinkedHashSet flavors = getNativeToFlavor().get(nat); - if (flavors == null) { - flavors = new LinkedHashSet<>(1); - getNativeToFlavor().put(nat, flavors); - } - flavors.add(flav); - flavorsForNativeCache.remove(nat); - } - - /** - * Discards the current mappings for the specified String - * native, and creates new mappings to the specified - * DataFlavors. Unlike getFlavorsForNative, the - * mappings will only be established in one direction, and the natives need - * not be encoded. To establish two-way mappings, call - * setNativesForFlavor as well. The first - * DataFlavor in the array will represent the highest priority - * mapping. Subsequent DataFlavors will represent mappings of - * decreasing priority. - *

- * If the array contains several elements that reference equal - * DataFlavors, this method will establish new mappings - * for the first of those elements and ignore the rest of them. - *

- * It is recommended that client code not reset mappings established by the - * data transfer subsystem. This method should only be used for - * application-level mappings. - * - * @param nat the String native key for the mappings - * @param flavors the DataFlavor values for the mappings - * @throws NullPointerException if nat or flavors is null - * or if flavors contains null elements - * - * @see #setNativesForFlavor - * @since 1.4 - */ - public synchronized void setFlavorsForNative(String nat, - DataFlavor[] flavors) { - Objects.requireNonNull(nat, "Null native not permitted"); - Objects.requireNonNull(flavors, "Null flavors not permitted"); - - getNativeToFlavor().remove(nat); - for (DataFlavor flavor : flavors) { - addFlavorForUnencodedNative(nat, flavor); - } - disabledMappingGenerationKeys.add(nat); - flavorsForNativeCache.remove(nat); - } - - /** - * Encodes a MIME type for use as a String native. The format - * of an encoded representation of a MIME type is implementation-dependent. - * The only restrictions are: - *

    - *
  • The encoded representation is null if and only if the - * MIME type String is null.
  • - *
  • The encoded representations for two non-null MIME type - * Strings are equal if and only if these Strings - * are equal according to String.equals(Object).
  • - *
- *

- * The reference implementation of this method returns the specified MIME - * type String prefixed with JAVA_DATAFLAVOR:. - * - * @param mimeType the MIME type to encode - * @return the encoded String, or null if - * mimeType is null - */ - public static String encodeJavaMIMEType(String mimeType) { - return (mimeType != null) - ? JavaMIME + mimeType - : null; - } - - /** - * Encodes a DataFlavor for use as a String - * native. The format of an encoded DataFlavor is - * implementation-dependent. The only restrictions are: - *

    - *
  • The encoded representation is null if and only if the - * specified DataFlavor is null or its MIME type - * String is null.
  • - *
  • The encoded representations for two non-null - * DataFlavors with non-null MIME type - * Strings are equal if and only if the MIME type - * Strings of these DataFlavors are equal - * according to String.equals(Object).
  • - *
- *

- * The reference implementation of this method returns the MIME type - * String of the specified DataFlavor prefixed - * with JAVA_DATAFLAVOR:. - * - * @param flav the DataFlavor to encode - * @return the encoded String, or null if - * flav is null or has a null MIME type - */ - public static String encodeDataFlavor(DataFlavor flav) { - return (flav != null) - ? SystemFlavorMap.encodeJavaMIMEType(flav.getMimeType()) - : null; - } - - /** - * Returns whether the specified String is an encoded Java - * MIME type. - * - * @param str the String to test - * @return true if the String is encoded; - * false otherwise - */ - public static boolean isJavaMIMEType(String str) { - return (str != null && str.startsWith(JavaMIME, 0)); - } - - /** - * Decodes a String native for use as a Java MIME type. - * - * @param nat the String to decode - * @return the decoded Java MIME type, or null if nat is not - * an encoded String native - */ - public static String decodeJavaMIMEType(String nat) { - return (isJavaMIMEType(nat)) - ? nat.substring(JavaMIME.length(), nat.length()).trim() - : null; - } - - /** - * Decodes a String native for use as a - * DataFlavor. - * - * @param nat the String to decode - * @return the decoded DataFlavor, or null if - * nat is not an encoded String native - * @throws ClassNotFoundException if the class of the data flavor - * is not loaded - */ - public static DataFlavor decodeDataFlavor(String nat) - throws ClassNotFoundException - { - String retval_str = SystemFlavorMap.decodeJavaMIMEType(nat); - return (retval_str != null) - ? new DataFlavor(retval_str) - : null; - } - - private static final class SoftCache { - Map>> cache; - - public void put(K key, LinkedHashSet value) { - if (cache == null) { - cache = new HashMap<>(1); - } - cache.put(key, new SoftReference<>(value)); - } - - public void remove(K key) { - if (cache == null) return; - cache.remove(null); - cache.remove(key); - } - - public LinkedHashSet check(K key) { - if (cache == null) return null; - SoftReference> ref = cache.get(key); - if (ref != null) { - return ref.get(); - } - return null; - } - } -} --- /dev/null 2015-01-13 17:34:36.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/SystemFlavorMap.java 2015-01-13 17:34:21.510876200 +0400 @@ -0,0 +1,1094 @@ +/* + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.awt.datatransfer; + +import sun.datatransfer.DataFlavorUtil; +import sun.datatransfer.DesktopDatatransferService; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.ref.SoftReference; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * The SystemFlavorMap is a configurable map between "natives" (Strings), which + * correspond to platform-specific data formats, and "flavors" (DataFlavors), + * which correspond to platform-independent MIME types. This mapping is used + * by the data transfer subsystem to transfer data between Java and native + * applications, and between Java applications in separate VMs. + * + * @since 1.2 + */ +public final class SystemFlavorMap implements FlavorMap, FlavorTable { + + /** + * Constant prefix used to tag Java types converted to native platform + * type. + */ + private static String JavaMIME = "JAVA_DATAFLAVOR:"; + + private static final Object FLAVOR_MAP_KEY = new Object(); + + /** + * The list of valid, decoded text flavor representation classes, in order + * from best to worst. + */ + private static final String[] UNICODE_TEXT_CLASSES = { + "java.io.Reader", "java.lang.String", "java.nio.CharBuffer", "\"[C\"" + }; + + /** + * The list of valid, encoded text flavor representation classes, in order + * from best to worst. + */ + private static final String[] ENCODED_TEXT_CLASSES = { + "java.io.InputStream", "java.nio.ByteBuffer", "\"[B\"" + }; + + /** + * A String representing text/plain MIME type. + */ + private static final String TEXT_PLAIN_BASE_TYPE = "text/plain"; + + /** + * A String representing text/html MIME type. + */ + private static final String HTML_TEXT_BASE_TYPE = "text/html"; + + /** + * Maps native Strings to Lists of DataFlavors (or base type Strings for + * text DataFlavors). + * Do not use the field directly, use getNativeToFlavor() instead. + */ + private final Map> nativeToFlavor = new HashMap<>(); + + /** + * Accessor to nativeToFlavor map. Since we use lazy initialization we must + * use this accessor instead of direct access to the field which may not be + * initialized yet. This method will initialize the field if needed. + * + * @return nativeToFlavor + */ + private Map> getNativeToFlavor() { + if (!isMapInitialized) { + initSystemFlavorMap(); + } + return nativeToFlavor; + } + + /** + * Maps DataFlavors (or base type Strings for text DataFlavors) to Lists of + * native Strings. + * Do not use the field directly, use getFlavorToNative() instead. + */ + private final Map> flavorToNative = new HashMap<>(); + + /** + * Accessor to flavorToNative map. Since we use lazy initialization we must + * use this accessor instead of direct access to the field which may not be + * initialized yet. This method will initialize the field if needed. + * + * @return flavorToNative + */ + private synchronized Map> getFlavorToNative() { + if (!isMapInitialized) { + initSystemFlavorMap(); + } + return flavorToNative; + } + + /** + * Maps a text DataFlavor primary mime-type to the native. Used only to store + * standard mappings registered in the flavormap.properties + * Do not use this field directly, use getTextTypeToNative() instead. + */ + private Map> textTypeToNative = new HashMap<>(); + + /** + * Shows if the object has been initialized. + */ + private boolean isMapInitialized = false; + + /** + * An accessor to textTypeToNative map. Since we use lazy initialization we + * must use this accessor instead of direct access to the field which may not + * be initialized yet. This method will initialize the field if needed. + * + * @return textTypeToNative + */ + private synchronized Map> getTextTypeToNative() { + if (!isMapInitialized) { + initSystemFlavorMap(); + // From this point the map should not be modified + textTypeToNative = Collections.unmodifiableMap(textTypeToNative); + } + return textTypeToNative; + } + + /** + * Caches the result of getNativesForFlavor(). Maps DataFlavors to + * SoftReferences which reference LinkedHashSet of String natives. + */ + private final SoftCache nativesForFlavorCache = new SoftCache<>(); + + /** + * Caches the result getFlavorsForNative(). Maps String natives to + * SoftReferences which reference LinkedHashSet of DataFlavors. + */ + private final SoftCache flavorsForNativeCache = new SoftCache<>(); + + /** + * Dynamic mapping generation used for text mappings should not be applied + * to the DataFlavors and String natives for which the mappings have been + * explicitly specified with setFlavorsForNative() or + * setNativesForFlavor(). This keeps all such keys. + */ + private Set disabledMappingGenerationKeys = new HashSet<>(); + + /** + * Returns the default FlavorMap for this thread's ClassLoader. + * + * @return the default FlavorMap for this thread's ClassLoader + */ + public static FlavorMap getDefaultFlavorMap() { + return DataFlavorUtil.getDesktopService().getFlavorMap(SystemFlavorMap::new); + } + + private SystemFlavorMap() { + } + + /** + * Initializes a SystemFlavorMap by reading flavormap.properties + * For thread-safety must be called under lock on this. + */ + private void initSystemFlavorMap() { + if (isMapInitialized) { + return; + } + isMapInitialized = true; + + InputStream is = SystemFlavorMap.class.getResourceAsStream("/sun/datatransfer/resources/flavormap.properties"); + if (is == null) { + throw new InternalError("Default flavor mapping not found"); + } + + try (InputStreamReader isr = new InputStreamReader(is); + BufferedReader reader = new BufferedReader(isr)) { + String line; + while ((line = reader.readLine()) != null) { + line = line.trim(); + if (line.startsWith("#") || line.isEmpty()) continue; + while (line.endsWith("\\")) { + line = line.substring(0, line.length() - 1) + reader.readLine().trim(); + } + int delimiterPosition = line.indexOf('='); + String key = line.substring(0, delimiterPosition).replaceAll("\\ ", " "); + String[] values = line.substring(delimiterPosition + 1, line.length()).split(","); + for (String value : values) { + try { + value = loadConvert(value); + MimeType mime = new MimeType(value); + if ("text".equals(mime.getPrimaryType())) { + String charset = mime.getParameter("charset"); + if (DataFlavorUtil.doesSubtypeSupportCharset(mime.getSubType(), charset)) + { + // We need to store the charset and eoln + // parameters, if any, so that the + // DataTransferer will have this information + // for conversion into the native format. + DesktopDatatransferService desktopService = + DataFlavorUtil.getDesktopService(); + if (desktopService.isDesktopPresent()) { + desktopService.registerTextFlavorProperties( + key, charset, + mime.getParameter("eoln"), + mime.getParameter("terminators")); + } + } + + // But don't store any of these parameters in the + // DataFlavor itself for any text natives (even + // non-charset ones). The SystemFlavorMap will + // synthesize the appropriate mappings later. + mime.removeParameter("charset"); + mime.removeParameter("class"); + mime.removeParameter("eoln"); + mime.removeParameter("terminators"); + value = mime.toString(); + } + } catch (MimeTypeParseException e) { + e.printStackTrace(); + continue; + } + + DataFlavor flavor; + try { + flavor = new DataFlavor(value); + } catch (Exception e) { + try { + flavor = new DataFlavor(value, null); + } catch (Exception ee) { + ee.printStackTrace(); + continue; + } + } + + final LinkedHashSet dfs = new LinkedHashSet<>(); + dfs.add(flavor); + + if ("text".equals(flavor.getPrimaryType())) { + dfs.addAll(convertMimeTypeToDataFlavors(value)); + store(flavor.mimeType.getBaseType(), key, getTextTypeToNative()); + } + + for (DataFlavor df : dfs) { + store(df, key, getFlavorToNative()); + store(key, df, getNativeToFlavor()); + } + } + } + } catch (IOException e) { + throw new InternalError("Error reading default flavor mapping", e); + } + } + + // Copied from java.util.Properties + private static String loadConvert(String theString) { + char aChar; + int len = theString.length(); + StringBuilder outBuffer = new StringBuilder(len); + + for (int x = 0; x < len; ) { + aChar = theString.charAt(x++); + if (aChar == '\\') { + aChar = theString.charAt(x++); + if (aChar == 'u') { + // Read the xxxx + int value = 0; + for (int i = 0; i < 4; i++) { + aChar = theString.charAt(x++); + switch (aChar) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + value = (value << 4) + aChar - '0'; + break; + } + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': { + value = (value << 4) + 10 + aChar - 'a'; + break; + } + case 'A': case 'B': case 'C': + case 'D': case 'E': case 'F': { + value = (value << 4) + 10 + aChar - 'A'; + break; + } + default: { + throw new IllegalArgumentException( + "Malformed \\uxxxx encoding."); + } + } + } + outBuffer.append((char)value); + } else { + if (aChar == 't') { + aChar = '\t'; + } else if (aChar == 'r') { + aChar = '\r'; + } else if (aChar == 'n') { + aChar = '\n'; + } else if (aChar == 'f') { + aChar = '\f'; + } + outBuffer.append(aChar); + } + } else { + outBuffer.append(aChar); + } + } + return outBuffer.toString(); + } + + /** + * Stores the listed object under the specified hash key in map. Unlike a + * standard map, the listed object will not replace any object already at + * the appropriate Map location, but rather will be appended to a List + * stored in that location. + */ + private void store(H hashed, L listed, Map> map) { + LinkedHashSet list = map.get(hashed); + if (list == null) { + list = new LinkedHashSet<>(1); + map.put(hashed, list); + } + if (!list.contains(listed)) { + list.add(listed); + } + } + + /** + * Semantically equivalent to 'nativeToFlavor.get(nat)'. This method + * handles the case where 'nat' is not found in 'nativeToFlavor'. In that + * case, a new DataFlavor is synthesized, stored, and returned, if and + * only if the specified native is encoded as a Java MIME type. + */ + private LinkedHashSet nativeToFlavorLookup(String nat) { + LinkedHashSet flavors = getNativeToFlavor().get(nat); + + if (nat != null && !disabledMappingGenerationKeys.contains(nat)) { + DesktopDatatransferService desktopService = DataFlavorUtil.getDesktopService(); + if (desktopService.isDesktopPresent()) { + LinkedHashSet platformFlavors = + desktopService.getPlatformMappingsForNative(nat); + if (!platformFlavors.isEmpty()) { + if (flavors != null) { + // Prepending the platform-specific mappings ensures + // that the flavors added with + // addFlavorForUnencodedNative() are at the end of + // list. + platformFlavors.addAll(flavors); + } + flavors = platformFlavors; + } + } + } + + if (flavors == null && isJavaMIMEType(nat)) { + String decoded = decodeJavaMIMEType(nat); + DataFlavor flavor = null; + + try { + flavor = new DataFlavor(decoded); + } catch (Exception e) { + System.err.println("Exception \"" + e.getClass().getName() + + ": " + e.getMessage() + + "\"while constructing DataFlavor for: " + + decoded); + } + + if (flavor != null) { + flavors = new LinkedHashSet<>(1); + getNativeToFlavor().put(nat, flavors); + flavors.add(flavor); + flavorsForNativeCache.remove(nat); + + LinkedHashSet natives = getFlavorToNative().get(flavor); + if (natives == null) { + natives = new LinkedHashSet<>(1); + getFlavorToNative().put(flavor, natives); + } + natives.add(nat); + nativesForFlavorCache.remove(flavor); + } + } + + return (flavors != null) ? flavors : new LinkedHashSet<>(0); + } + + /** + * Semantically equivalent to 'flavorToNative.get(flav)'. This method + * handles the case where 'flav' is not found in 'flavorToNative' depending + * on the value of passes 'synthesize' parameter. If 'synthesize' is + * SYNTHESIZE_IF_NOT_FOUND a native is synthesized, stored, and returned by + * encoding the DataFlavor's MIME type. Otherwise an empty List is returned + * and 'flavorToNative' remains unaffected. + */ + private LinkedHashSet flavorToNativeLookup(final DataFlavor flav, + final boolean synthesize) { + + LinkedHashSet natives = getFlavorToNative().get(flav); + + if (flav != null && !disabledMappingGenerationKeys.contains(flav)) { + DesktopDatatransferService desktopService = DataFlavorUtil.getDesktopService(); + if (desktopService.isDesktopPresent()) { + LinkedHashSet platformNatives = + desktopService.getPlatformMappingsForFlavor(flav); + if (!platformNatives.isEmpty()) { + if (natives != null) { + // Prepend the platform-specific mappings to ensure + // that the natives added with + // addUnencodedNativeForFlavor() are at the end of + // list. + platformNatives.addAll(natives); + } + natives = platformNatives; + } + } + } + + if (natives == null) { + if (synthesize) { + String encoded = encodeDataFlavor(flav); + natives = new LinkedHashSet<>(1); + getFlavorToNative().put(flav, natives); + natives.add(encoded); + + LinkedHashSet flavors = getNativeToFlavor().get(encoded); + if (flavors == null) { + flavors = new LinkedHashSet<>(1); + getNativeToFlavor().put(encoded, flavors); + } + flavors.add(flav); + + nativesForFlavorCache.remove(flav); + flavorsForNativeCache.remove(encoded); + } else { + natives = new LinkedHashSet<>(0); + } + } + + return new LinkedHashSet<>(natives); + } + + /** + * Returns a List of String natives to which the + * specified DataFlavor can be translated by the data transfer + * subsystem. The List will be sorted from best native to + * worst. That is, the first native will best reflect data in the specified + * flavor to the underlying native platform. + *

+ * If the specified DataFlavor is previously unknown to the + * data transfer subsystem and the data transfer subsystem is unable to + * translate this DataFlavor to any existing native, then + * invoking this method will establish a + * mapping in both directions between the specified DataFlavor + * and an encoded version of its MIME type as its native. + * + * @param flav the DataFlavor whose corresponding natives + * should be returned. If null is specified, all + * natives currently known to the data transfer subsystem are + * returned in a non-deterministic order. + * @return a java.util.List of java.lang.String + * objects which are platform-specific representations of platform- + * specific data formats + * + * @see #encodeDataFlavor + * @since 1.4 + */ + @Override + public synchronized List getNativesForFlavor(DataFlavor flav) { + LinkedHashSet retval = nativesForFlavorCache.check(flav); + if (retval != null) { + return new ArrayList<>(retval); + } + + if (flav == null) { + retval = new LinkedHashSet<>(getNativeToFlavor().keySet()); + } else if (disabledMappingGenerationKeys.contains(flav)) { + // In this case we shouldn't synthesize a native for this flavor, + // since its mappings were explicitly specified. + retval = flavorToNativeLookup(flav, false); + } else if (DataFlavorUtil.isFlavorCharsetTextType(flav)) { + retval = new LinkedHashSet<>(0); + + // For text/* flavors, flavor-to-native mappings specified in + // flavormap.properties are stored per flavor's base type. + if ("text".equals(flav.getPrimaryType())) { + LinkedHashSet textTypeNatives = + getTextTypeToNative().get(flav.mimeType.getBaseType()); + if (textTypeNatives != null) { + retval.addAll(textTypeNatives); + } + } + + // Also include text/plain natives, but don't duplicate Strings + LinkedHashSet textTypeNatives = + getTextTypeToNative().get(TEXT_PLAIN_BASE_TYPE); + if (textTypeNatives != null) { + retval.addAll(textTypeNatives); + } + + if (retval.isEmpty()) { + retval = flavorToNativeLookup(flav, true); + } else { + // In this branch it is guaranteed that natives explicitly + // listed for flav's MIME type were added with + // addUnencodedNativeForFlavor(), so they have lower priority. + retval.addAll(flavorToNativeLookup(flav, false)); + } + } else if (DataFlavorUtil.isFlavorNoncharsetTextType(flav)) { + retval = getTextTypeToNative().get(flav.mimeType.getBaseType()); + + if (retval == null || retval.isEmpty()) { + retval = flavorToNativeLookup(flav, true); + } else { + // In this branch it is guaranteed that natives explicitly + // listed for flav's MIME type were added with + // addUnencodedNativeForFlavor(), so they have lower priority. + retval.addAll(flavorToNativeLookup(flav, false)); + } + } else { + retval = flavorToNativeLookup(flav, true); + } + + nativesForFlavorCache.put(flav, retval); + // Create a copy, because client code can modify the returned list. + return new ArrayList<>(retval); + } + + /** + * Returns a List of DataFlavors to which the + * specified String native can be translated by the data + * transfer subsystem. The List will be sorted from best + * DataFlavor to worst. That is, the first + * DataFlavor will best reflect data in the specified + * native to a Java application. + *

+ * If the specified native is previously unknown to the data transfer + * subsystem, and that native has been properly encoded, then invoking this + * method will establish a mapping in both directions between the specified + * native and a DataFlavor whose MIME type is a decoded + * version of the native. + *

+ * If the specified native is not a properly encoded native and the + * mappings for this native have not been altered with + * setFlavorsForNative, then the contents of the + * List is platform dependent, but null + * cannot be returned. + * + * @param nat the native whose corresponding DataFlavors + * should be returned. If null is specified, all + * DataFlavors currently known to the data transfer + * subsystem are returned in a non-deterministic order. + * @return a java.util.List of DataFlavor + * objects into which platform-specific data in the specified, + * platform-specific native can be translated + * + * @see #encodeJavaMIMEType + * @since 1.4 + */ + @Override + public synchronized List getFlavorsForNative(String nat) { + LinkedHashSet returnValue = flavorsForNativeCache.check(nat); + if (returnValue != null) { + return new ArrayList<>(returnValue); + } else { + returnValue = new LinkedHashSet<>(); + } + + if (nat == null) { + for (String n : getNativesForFlavor(null)) { + returnValue.addAll(getFlavorsForNative(n)); + } + } else { + final LinkedHashSet flavors = nativeToFlavorLookup(nat); + if (disabledMappingGenerationKeys.contains(nat)) { + return new ArrayList<>(flavors); + } + + final LinkedHashSet flavorsWithSynthesized = + nativeToFlavorLookup(nat); + + for (DataFlavor df : flavorsWithSynthesized) { + returnValue.add(df); + if ("text".equals(df.getPrimaryType())) { + String baseType = df.mimeType.getBaseType(); + returnValue.addAll(convertMimeTypeToDataFlavors(baseType)); + } + } + } + flavorsForNativeCache.put(nat, returnValue); + return new ArrayList<>(returnValue); + } + + @SuppressWarnings("deprecation") + private static Set convertMimeTypeToDataFlavors( + final String baseType) { + + final Set returnValue = new LinkedHashSet<>(); + + String subType = null; + + try { + final MimeType mimeType = new MimeType(baseType); + subType = mimeType.getSubType(); + } catch (MimeTypeParseException mtpe) { + // Cannot happen, since we checked all mappings + // on load from flavormap.properties. + } + + if (DataFlavorUtil.doesSubtypeSupportCharset(subType, null)) { + if (TEXT_PLAIN_BASE_TYPE.equals(baseType)) + { + returnValue.add(DataFlavor.stringFlavor); + } + + for (String unicodeClassName : UNICODE_TEXT_CLASSES) { + final String mimeType = baseType + ";charset=Unicode;class=" + + unicodeClassName; + + final LinkedHashSet mimeTypes = + handleHtmlMimeTypes(baseType, mimeType); + for (String mt : mimeTypes) { + DataFlavor toAdd = null; + try { + toAdd = new DataFlavor(mt); + } catch (ClassNotFoundException cannotHappen) { + } + returnValue.add(toAdd); + } + } + + for (String charset : DataFlavorUtil.standardEncodings()) { + + for (String encodedTextClass : ENCODED_TEXT_CLASSES) { + final String mimeType = + baseType + ";charset=" + charset + + ";class=" + encodedTextClass; + + final LinkedHashSet mimeTypes = + handleHtmlMimeTypes(baseType, mimeType); + + for (String mt : mimeTypes) { + + DataFlavor df = null; + + try { + df = new DataFlavor(mt); + // Check for equality to plainTextFlavor so + // that we can ensure that the exact charset of + // plainTextFlavor, not the canonical charset + // or another equivalent charset with a + // different name, is used. + if (df.equals(DataFlavor.plainTextFlavor)) { + df = DataFlavor.plainTextFlavor; + } + } catch (ClassNotFoundException cannotHappen) { + } + + returnValue.add(df); + } + } + } + + if (TEXT_PLAIN_BASE_TYPE.equals(baseType)) + { + returnValue.add(DataFlavor.plainTextFlavor); + } + } else { + // Non-charset text natives should be treated as + // opaque, 8-bit data in any of its various + // representations. + for (String encodedTextClassName : ENCODED_TEXT_CLASSES) { + DataFlavor toAdd = null; + try { + toAdd = new DataFlavor(baseType + + ";class=" + encodedTextClassName); + } catch (ClassNotFoundException cannotHappen) { + } + returnValue.add(toAdd); + } + } + return returnValue; + } + + private static final String [] htmlDocumentTypes = + new String [] {"all", "selection", "fragment"}; + + private static LinkedHashSet handleHtmlMimeTypes(String baseType, + String mimeType) { + + LinkedHashSet returnValues = new LinkedHashSet<>(); + + if (HTML_TEXT_BASE_TYPE.equals(baseType)) { + for (String documentType : htmlDocumentTypes) { + returnValues.add(mimeType + ";document=" + documentType); + } + } else { + returnValues.add(mimeType); + } + + return returnValues; + } + + /** + * Returns a Map of the specified DataFlavors to + * their most preferred String native. Each native value will + * be the same as the first native in the List returned by + * getNativesForFlavor for the specified flavor. + *

+ * If a specified DataFlavor is previously unknown to the + * data transfer subsystem, then invoking this method will establish a + * mapping in both directions between the specified DataFlavor + * and an encoded version of its MIME type as its native. + * + * @param flavors an array of DataFlavors which will be the + * key set of the returned Map. If null is + * specified, a mapping of all DataFlavors known to the + * data transfer subsystem to their most preferred + * String natives will be returned. + * @return a java.util.Map of DataFlavors to + * String natives + * + * @see #getNativesForFlavor + * @see #encodeDataFlavor + */ + @Override + public synchronized Map getNativesForFlavors(DataFlavor[] flavors) + { + // Use getNativesForFlavor to generate extra natives for text flavors + // and stringFlavor + + if (flavors == null) { + List flavor_list = getFlavorsForNative(null); + flavors = new DataFlavor[flavor_list.size()]; + flavor_list.toArray(flavors); + } + + Map retval = new HashMap<>(flavors.length, 1.0f); + for (DataFlavor flavor : flavors) { + List natives = getNativesForFlavor(flavor); + String nat = (natives.isEmpty()) ? null : natives.get(0); + retval.put(flavor, nat); + } + + return retval; + } + + /** + * Returns a Map of the specified String natives + * to their most preferred DataFlavor. Each + * DataFlavor value will be the same as the first + * DataFlavor in the List returned by + * getFlavorsForNative for the specified native. + *

+ * If a specified native is previously unknown to the data transfer + * subsystem, and that native has been properly encoded, then invoking this + * method will establish a mapping in both directions between the specified + * native and a DataFlavor whose MIME type is a decoded + * version of the native. + * + * @param natives an array of Strings which will be the + * key set of the returned Map. If null is + * specified, a mapping of all supported String natives + * to their most preferred DataFlavors will be + * returned. + * @return a java.util.Map of String natives to + * DataFlavors + * + * @see #getFlavorsForNative + * @see #encodeJavaMIMEType + */ + @Override + public synchronized Map getFlavorsForNatives(String[] natives) + { + // Use getFlavorsForNative to generate extra flavors for text natives + if (natives == null) { + List nativesList = getNativesForFlavor(null); + natives = new String[nativesList.size()]; + nativesList.toArray(natives); + } + + Map retval = new HashMap<>(natives.length, 1.0f); + for (String aNative : natives) { + List flavors = getFlavorsForNative(aNative); + DataFlavor flav = (flavors.isEmpty())? null : flavors.get(0); + retval.put(aNative, flav); + } + return retval; + } + + /** + * Adds a mapping from the specified DataFlavor (and all + * DataFlavors equal to the specified DataFlavor) + * to the specified String native. + * Unlike getNativesForFlavor, the mapping will only be + * established in one direction, and the native will not be encoded. To + * establish a two-way mapping, call + * addFlavorForUnencodedNative as well. The new mapping will + * be of lower priority than any existing mapping. + * This method has no effect if a mapping from the specified or equal + * DataFlavor to the specified String native + * already exists. + * + * @param flav the DataFlavor key for the mapping + * @param nat the String native value for the mapping + * @throws NullPointerException if flav or nat is null + * + * @see #addFlavorForUnencodedNative + * @since 1.4 + */ + public synchronized void addUnencodedNativeForFlavor(DataFlavor flav, + String nat) { + Objects.requireNonNull(nat, "Null native not permitted"); + Objects.requireNonNull(flav, "Null flavor not permitted"); + + LinkedHashSet natives = getFlavorToNative().get(flav); + if (natives == null) { + natives = new LinkedHashSet<>(1); + getFlavorToNative().put(flav, natives); + } + natives.add(nat); + nativesForFlavorCache.remove(flav); + } + + /** + * Discards the current mappings for the specified DataFlavor + * and all DataFlavors equal to the specified + * DataFlavor, and creates new mappings to the + * specified String natives. + * Unlike getNativesForFlavor, the mappings will only be + * established in one direction, and the natives will not be encoded. To + * establish two-way mappings, call setFlavorsForNative + * as well. The first native in the array will represent the highest + * priority mapping. Subsequent natives will represent mappings of + * decreasing priority. + *

+ * If the array contains several elements that reference equal + * String natives, this method will establish new mappings + * for the first of those elements and ignore the rest of them. + *

+ * It is recommended that client code not reset mappings established by the + * data transfer subsystem. This method should only be used for + * application-level mappings. + * + * @param flav the DataFlavor key for the mappings + * @param natives the String native values for the mappings + * @throws NullPointerException if flav or natives is null + * or if natives contains null elements + * + * @see #setFlavorsForNative + * @since 1.4 + */ + public synchronized void setNativesForFlavor(DataFlavor flav, + String[] natives) { + Objects.requireNonNull(natives, "Null natives not permitted"); + Objects.requireNonNull(flav, "Null flavors not permitted"); + + getFlavorToNative().remove(flav); + for (String aNative : natives) { + addUnencodedNativeForFlavor(flav, aNative); + } + disabledMappingGenerationKeys.add(flav); + nativesForFlavorCache.remove(flav); + } + + /** + * Adds a mapping from a single String native to a single + * DataFlavor. Unlike getFlavorsForNative, the + * mapping will only be established in one direction, and the native will + * not be encoded. To establish a two-way mapping, call + * addUnencodedNativeForFlavor as well. The new mapping will + * be of lower priority than any existing mapping. + * This method has no effect if a mapping from the specified + * String native to the specified or equal + * DataFlavor already exists. + * + * @param nat the String native key for the mapping + * @param flav the DataFlavor value for the mapping + * @throws NullPointerException if nat or flav is null + * + * @see #addUnencodedNativeForFlavor + * @since 1.4 + */ + public synchronized void addFlavorForUnencodedNative(String nat, + DataFlavor flav) { + Objects.requireNonNull(nat, "Null native not permitted"); + Objects.requireNonNull(flav, "Null flavor not permitted"); + + LinkedHashSet flavors = getNativeToFlavor().get(nat); + if (flavors == null) { + flavors = new LinkedHashSet<>(1); + getNativeToFlavor().put(nat, flavors); + } + flavors.add(flav); + flavorsForNativeCache.remove(nat); + } + + /** + * Discards the current mappings for the specified String + * native, and creates new mappings to the specified + * DataFlavors. Unlike getFlavorsForNative, the + * mappings will only be established in one direction, and the natives need + * not be encoded. To establish two-way mappings, call + * setNativesForFlavor as well. The first + * DataFlavor in the array will represent the highest priority + * mapping. Subsequent DataFlavors will represent mappings of + * decreasing priority. + *

+ * If the array contains several elements that reference equal + * DataFlavors, this method will establish new mappings + * for the first of those elements and ignore the rest of them. + *

+ * It is recommended that client code not reset mappings established by the + * data transfer subsystem. This method should only be used for + * application-level mappings. + * + * @param nat the String native key for the mappings + * @param flavors the DataFlavor values for the mappings + * @throws NullPointerException if nat or flavors is null + * or if flavors contains null elements + * + * @see #setNativesForFlavor + * @since 1.4 + */ + public synchronized void setFlavorsForNative(String nat, + DataFlavor[] flavors) { + Objects.requireNonNull(nat, "Null native not permitted"); + Objects.requireNonNull(flavors, "Null flavors not permitted"); + + getNativeToFlavor().remove(nat); + for (DataFlavor flavor : flavors) { + addFlavorForUnencodedNative(nat, flavor); + } + disabledMappingGenerationKeys.add(nat); + flavorsForNativeCache.remove(nat); + } + + /** + * Encodes a MIME type for use as a String native. The format + * of an encoded representation of a MIME type is implementation-dependent. + * The only restrictions are: + *

    + *
  • The encoded representation is null if and only if the + * MIME type String is null.
  • + *
  • The encoded representations for two non-null MIME type + * Strings are equal if and only if these Strings + * are equal according to String.equals(Object).
  • + *
+ *

+ * The reference implementation of this method returns the specified MIME + * type String prefixed with JAVA_DATAFLAVOR:. + * + * @param mimeType the MIME type to encode + * @return the encoded String, or null if + * mimeType is null + */ + public static String encodeJavaMIMEType(String mimeType) { + return (mimeType != null) + ? JavaMIME + mimeType + : null; + } + + /** + * Encodes a DataFlavor for use as a String + * native. The format of an encoded DataFlavor is + * implementation-dependent. The only restrictions are: + *

    + *
  • The encoded representation is null if and only if the + * specified DataFlavor is null or its MIME type + * String is null.
  • + *
  • The encoded representations for two non-null + * DataFlavors with non-null MIME type + * Strings are equal if and only if the MIME type + * Strings of these DataFlavors are equal + * according to String.equals(Object).
  • + *
+ *

+ * The reference implementation of this method returns the MIME type + * String of the specified DataFlavor prefixed + * with JAVA_DATAFLAVOR:. + * + * @param flav the DataFlavor to encode + * @return the encoded String, or null if + * flav is null or has a null MIME type + */ + public static String encodeDataFlavor(DataFlavor flav) { + return (flav != null) + ? SystemFlavorMap.encodeJavaMIMEType(flav.getMimeType()) + : null; + } + + /** + * Returns whether the specified String is an encoded Java + * MIME type. + * + * @param str the String to test + * @return true if the String is encoded; + * false otherwise + */ + public static boolean isJavaMIMEType(String str) { + return (str != null && str.startsWith(JavaMIME, 0)); + } + + /** + * Decodes a String native for use as a Java MIME type. + * + * @param nat the String to decode + * @return the decoded Java MIME type, or null if nat is not + * an encoded String native + */ + public static String decodeJavaMIMEType(String nat) { + return (isJavaMIMEType(nat)) + ? nat.substring(JavaMIME.length(), nat.length()).trim() + : null; + } + + /** + * Decodes a String native for use as a + * DataFlavor. + * + * @param nat the String to decode + * @return the decoded DataFlavor, or null if + * nat is not an encoded String native + * @throws ClassNotFoundException if the class of the data flavor + * is not loaded + */ + public static DataFlavor decodeDataFlavor(String nat) + throws ClassNotFoundException + { + String retval_str = SystemFlavorMap.decodeJavaMIMEType(nat); + return (retval_str != null) + ? new DataFlavor(retval_str) + : null; + } + + private static final class SoftCache { + Map>> cache; + + public void put(K key, LinkedHashSet value) { + if (cache == null) { + cache = new HashMap<>(1); + } + cache.put(key, new SoftReference<>(value)); + } + + public void remove(K key) { + if (cache == null) return; + cache.remove(null); + cache.remove(key); + } + + public LinkedHashSet check(K key) { + if (cache == null) return null; + SoftReference> ref = cache.get(key); + if (ref != null) { + return ref.get(); + } + return null; + } + } +} --- old/src/java.desktop/share/classes/java/awt/datatransfer/Transferable.java 2015-01-13 17:34:46.955331500 +0400 +++ /dev/null 2015-01-13 17:34:47.000000000 +0400 @@ -1,74 +0,0 @@ -/* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.awt.datatransfer; - -import java.io.IOException; - -/** - * Defines the interface for classes that can be used to provide data - * for a transfer operation. - *

- * For information on using data transfer with Swing, see - * - * How to Use Drag and Drop and Data Transfer, - * a section in The Java Tutorial, for more information. - * - * @author Amy Fowler - */ - -public interface Transferable { - - /** - * Returns an array of DataFlavor objects indicating the flavors the data - * can be provided in. The array should be ordered according to preference - * for providing the data (from most richly descriptive to least descriptive). - * @return an array of data flavors in which this data can be transferred - */ - public DataFlavor[] getTransferDataFlavors(); - - /** - * Returns whether or not the specified data flavor is supported for - * this object. - * @param flavor the requested flavor for the data - * @return boolean indicating whether or not the data flavor is supported - */ - public boolean isDataFlavorSupported(DataFlavor flavor); - - /** - * Returns an object which represents the data to be transferred. The class - * of the object returned is defined by the representation class of the flavor. - * - * @param flavor the requested flavor for the data - * @return an object which represents the data to be transferred - * @see DataFlavor#getRepresentationClass - * @exception IOException if the data is no longer available - * in the requested flavor. - * @exception UnsupportedFlavorException if the requested data flavor is - * not supported. - */ - public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException; - -} --- /dev/null 2015-01-13 17:34:47.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/Transferable.java 2015-01-13 17:34:46.511306100 +0400 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.awt.datatransfer; + +import java.io.IOException; + +/** + * Defines the interface for classes that can be used to provide data + * for a transfer operation. + *

+ * For information on using data transfer with Swing, see + * + * How to Use Drag and Drop and Data Transfer, + * a section in The Java Tutorial, for more information. + * + * @author Amy Fowler + */ + +public interface Transferable { + + /** + * Returns an array of DataFlavor objects indicating the flavors the data + * can be provided in. The array should be ordered according to preference + * for providing the data (from most richly descriptive to least descriptive). + * @return an array of data flavors in which this data can be transferred + */ + public DataFlavor[] getTransferDataFlavors(); + + /** + * Returns whether or not the specified data flavor is supported for + * this object. + * @param flavor the requested flavor for the data + * @return boolean indicating whether or not the data flavor is supported + */ + public boolean isDataFlavorSupported(DataFlavor flavor); + + /** + * Returns an object which represents the data to be transferred. The class + * of the object returned is defined by the representation class of the flavor. + * + * @param flavor the requested flavor for the data + * @return an object which represents the data to be transferred + * @see DataFlavor#getRepresentationClass + * @exception IOException if the data is no longer available + * in the requested flavor. + * @exception UnsupportedFlavorException if the requested data flavor is + * not supported. + */ + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException; + +} --- old/src/java.desktop/share/classes/java/awt/datatransfer/UnsupportedFlavorException.java 2015-01-13 17:34:51.211575000 +0400 +++ /dev/null 2015-01-13 17:34:52.000000000 +0400 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.awt.datatransfer; - -/** - * Signals that the requested data is not supported in this flavor. - * @see Transferable#getTransferData - * - * @author Amy Fowler - */ -public class UnsupportedFlavorException extends Exception { - - /* - * JDK 1.1 serialVersionUID - */ - private static final long serialVersionUID = 5383814944251665601L; - - /** - * Constructs an UnsupportedFlavorException. - * - * @param flavor the flavor object which caused the exception. May - * be null. - */ - public UnsupportedFlavorException(DataFlavor flavor) { - super((flavor != null) ? flavor.getHumanPresentableName() : null); - } -} --- /dev/null 2015-01-13 17:34:52.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/UnsupportedFlavorException.java 2015-01-13 17:34:50.352525800 +0400 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.awt.datatransfer; + +/** + * Signals that the requested data is not supported in this flavor. + * @see Transferable#getTransferData + * + * @author Amy Fowler + */ +public class UnsupportedFlavorException extends Exception { + + /* + * JDK 1.1 serialVersionUID + */ + private static final long serialVersionUID = 5383814944251665601L; + + /** + * Constructs an UnsupportedFlavorException. + * + * @param flavor the flavor object which caused the exception. May + * be null. + */ + public UnsupportedFlavorException(DataFlavor flavor) { + super((flavor != null) ? flavor.getHumanPresentableName() : null); + } +} --- old/src/java.desktop/share/classes/java/awt/datatransfer/package.html 2015-01-13 17:35:02.446215300 +0400 +++ /dev/null 2015-01-13 17:35:16.000000000 +0400 @@ -1,64 +0,0 @@ - - - - - - - -Provides interfaces and classes for transferring data -between and within applications. It defines the notion of a -"transferable" object, which is an object capable of being -transferred between or within applications. An object identifies -itself as being transferable by implementing the Transferable -interface. -

-It also provides a clipboard mechanism, which is an object that -temporarily holds a transferable object that can be transferred -between or within an application. The clipboard is typically used -for copy and paste operations. Although it is possible to create -a clipboard to use within an application, most applications will -use the system clipboard to ensure the data can be transferred -across applications running on the platform. - - - -@since 1.1 - - --- /dev/null 2015-01-13 17:35:17.000000000 +0400 +++ new/src/java.datatransfer/share/classes/java/awt/datatransfer/package.html 2015-01-13 17:34:59.915070500 +0400 @@ -0,0 +1,64 @@ + + + + + + + +Provides interfaces and classes for transferring data +between and within applications. It defines the notion of a +"transferable" object, which is an object capable of being +transferred between or within applications. An object identifies +itself as being transferable by implementing the Transferable +interface. +

+It also provides a clipboard mechanism, which is an object that +temporarily holds a transferable object that can be transferred +between or within an application. The clipboard is typically used +for copy and paste operations. Although it is possible to create +a clipboard to use within an application, most applications will +use the system clipboard to ensure the data can be transferred +across applications running on the platform. + + + +@since 1.1 + + --- old/src/java.desktop/share/classes/sun/datatransfer/DataFlavorUtil.java 2015-01-13 17:35:20.421243400 +0400 +++ /dev/null 2015-01-13 17:35:23.000000000 +0400 @@ -1,841 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.datatransfer; - -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.FlavorMap; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.IllegalCharsetNameException; -import java.nio.charset.StandardCharsets; -import java.nio.charset.UnsupportedCharsetException; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.function.Supplier; - - -/** - * Utility class with different datatransfer helper functions - * - * @see 1.9 - */ -public class DataFlavorUtil { - - private DataFlavorUtil() { - // Avoid instantiation - } - - private static Comparator getCharsetComparator() { - return CharsetComparator.INSTANCE; - } - - public static Comparator getDataFlavorComparator() { - return DataFlavorComparator.INSTANCE; - } - - public static Comparator getIndexOrderComparator(Map indexMap) { - return new IndexOrderComparator(indexMap); - } - - public static Comparator getTextFlavorComparator() { - return TextFlavorComparator.INSTANCE; - } - - /** - * Tracks whether a particular text/* MIME type supports the charset - * parameter. The Map is initialized with all of the standard MIME types - * listed in the DataFlavor.selectBestTextFlavor method comment. Additional - * entries may be added during the life of the JRE for text/ types. - */ - private static final Map textMIMESubtypeCharsetSupport; - - static { - Map tempMap = new HashMap<>(17); - tempMap.put("sgml", Boolean.TRUE); - tempMap.put("xml", Boolean.TRUE); - tempMap.put("html", Boolean.TRUE); - tempMap.put("enriched", Boolean.TRUE); - tempMap.put("richtext", Boolean.TRUE); - tempMap.put("uri-list", Boolean.TRUE); - tempMap.put("directory", Boolean.TRUE); - tempMap.put("css", Boolean.TRUE); - tempMap.put("calendar", Boolean.TRUE); - tempMap.put("plain", Boolean.TRUE); - tempMap.put("rtf", Boolean.FALSE); - tempMap.put("tab-separated-values", Boolean.FALSE); - tempMap.put("t140", Boolean.FALSE); - tempMap.put("rfc822-headers", Boolean.FALSE); - tempMap.put("parityfec", Boolean.FALSE); - textMIMESubtypeCharsetSupport = Collections.synchronizedMap(tempMap); - } - - /** - * Lazy initialization of Standard Encodings. - */ - private static class StandardEncodingsHolder { - private static final SortedSet standardEncodings = load(); - - private static SortedSet load() { - final SortedSet tempSet = new TreeSet<>(getCharsetComparator().reversed()); - tempSet.add("US-ASCII"); - tempSet.add("ISO-8859-1"); - tempSet.add("UTF-8"); - tempSet.add("UTF-16BE"); - tempSet.add("UTF-16LE"); - tempSet.add("UTF-16"); - tempSet.add(Charset.defaultCharset().name()); - return Collections.unmodifiableSortedSet(tempSet); - } - } - - /** - * Returns a {@code SortedSet} of Strings which are a total order of the standard - * character sets supported by the JRE. The ordering follows the same principles as - * {@link java.awt.datatransfer.DataFlavor#selectBestTextFlavor(java.awt.datatransfer.DataFlavor[])}. - * So as to avoid loading all available character converters, optional, non-standard, - * character sets are not included. - */ - public static Set standardEncodings() { - return StandardEncodingsHolder.standardEncodings; - } - - /** - * Converts an arbitrary text encoding to its canonical name. - */ - public static String canonicalName(String encoding) { - if (encoding == null) { - return null; - } - try { - return Charset.forName(encoding).name(); - } catch (IllegalCharsetNameException icne) { - return encoding; - } catch (UnsupportedCharsetException uce) { - return encoding; - } - } - - /** - * Tests only whether the flavor's MIME type supports the charset - * parameter. Must only be called for flavors with a primary type of - * "text". - */ - public static boolean doesSubtypeSupportCharset(DataFlavor flavor) { - String subType = flavor.getSubType(); - if (subType == null) { - return false; - } - - Boolean support = textMIMESubtypeCharsetSupport.get(subType); - - if (support != null) { - return support; - } - - boolean ret_val = (flavor.getParameter("charset") != null); - textMIMESubtypeCharsetSupport.put(subType, ret_val); - return ret_val; - } - public static boolean doesSubtypeSupportCharset(String subType, - String charset) - { - Boolean support = textMIMESubtypeCharsetSupport.get(subType); - - if (support != null) { - return support; - } - - boolean ret_val = (charset != null); - textMIMESubtypeCharsetSupport.put(subType, ret_val); - return ret_val; - } - - - /** - * Returns whether this flavor is a text type which supports the - * 'charset' parameter. - */ - public static boolean isFlavorCharsetTextType(DataFlavor flavor) { - // Although stringFlavor doesn't actually support the charset - // parameter (because its primary MIME type is not "text"), it should - // be treated as though it does. stringFlavor is semantically - // equivalent to "text/plain" data. - if (DataFlavor.stringFlavor.equals(flavor)) { - return true; - } - - if (!"text".equals(flavor.getPrimaryType()) || - !doesSubtypeSupportCharset(flavor)) - { - return false; - } - - Class rep_class = flavor.getRepresentationClass(); - - if (flavor.isRepresentationClassReader() || - String.class.equals(rep_class) || - flavor.isRepresentationClassCharBuffer() || - char[].class.equals(rep_class)) - { - return true; - } - - if (!(flavor.isRepresentationClassInputStream() || - flavor.isRepresentationClassByteBuffer() || - byte[].class.equals(rep_class))) { - return false; - } - - String charset = flavor.getParameter("charset"); - - // null equals default encoding which is always supported - return (charset == null) || isEncodingSupported(charset); - } - - /** - * Returns whether this flavor is a text type which does not support the - * 'charset' parameter. - */ - public static boolean isFlavorNoncharsetTextType(DataFlavor flavor) { - if (!"text".equals(flavor.getPrimaryType()) || doesSubtypeSupportCharset(flavor)) { - return false; - } - - return (flavor.isRepresentationClassInputStream() || - flavor.isRepresentationClassByteBuffer() || - byte[].class.equals(flavor.getRepresentationClass())); - } - - /** - * If the specified flavor is a text flavor which supports the "charset" - * parameter, then this method returns that parameter, or the default - * charset if no such parameter was specified at construction. For non- - * text DataFlavors, and for non-charset text flavors, this method returns - * null. - */ - public static String getTextCharset(DataFlavor flavor) { - if (!isFlavorCharsetTextType(flavor)) { - return null; - } - - String encoding = flavor.getParameter("charset"); - - return (encoding != null) ? encoding : Charset.defaultCharset().name(); - } - - /** - * Determines whether this JRE can both encode and decode text in the - * specified encoding. - */ - private static boolean isEncodingSupported(String encoding) { - if (encoding == null) { - return false; - } - try { - return Charset.isSupported(encoding); - } catch (IllegalCharsetNameException icne) { - return false; - } - } - - /** - * Helper method to compare two objects by their Integer indices in the - * given map. If the map doesn't contain an entry for either of the - * objects, the fallback index will be used for the object instead. - * - * @param indexMap the map which maps objects into Integer indexes. - * @param obj1 the first object to be compared. - * @param obj2 the second object to be compared. - * @param fallbackIndex the Integer to be used as a fallback index. - * @return a negative integer, zero, or a positive integer as the - * first object is mapped to a less, equal to, or greater - * index than the second. - */ - static int compareIndices(Map indexMap, - T obj1, T obj2, - Integer fallbackIndex) { - Integer index1 = indexMap.getOrDefault(obj1, fallbackIndex); - Integer index2 = indexMap.getOrDefault(obj2, fallbackIndex); - return index1.compareTo(index2); - } - - /** - * An IndexedComparator which compares two String charsets. The comparison - * follows the rules outlined in DataFlavor.selectBestTextFlavor. In order - * to ensure that non-Unicode, non-ASCII, non-default charsets are sorted - * in alphabetical order, charsets are not automatically converted to their - * canonical forms. - */ - private static class CharsetComparator implements Comparator { - static final CharsetComparator INSTANCE = new CharsetComparator(); - - private static final Map charsets; - - private static final Integer DEFAULT_CHARSET_INDEX = 2; - private static final Integer OTHER_CHARSET_INDEX = 1; - private static final Integer WORST_CHARSET_INDEX = 0; - private static final Integer UNSUPPORTED_CHARSET_INDEX = Integer.MIN_VALUE; - - private static final String UNSUPPORTED_CHARSET = "UNSUPPORTED"; - - static { - Map charsetsMap = new HashMap<>(8, 1.0f); - - // we prefer Unicode charsets - charsetsMap.put(canonicalName("UTF-16LE"), 4); - charsetsMap.put(canonicalName("UTF-16BE"), 5); - charsetsMap.put(canonicalName("UTF-8"), 6); - charsetsMap.put(canonicalName("UTF-16"), 7); - - // US-ASCII is the worst charset supported - charsetsMap.put(canonicalName("US-ASCII"), WORST_CHARSET_INDEX); - - charsetsMap.putIfAbsent(Charset.defaultCharset().name(), DEFAULT_CHARSET_INDEX); - - charsetsMap.put(UNSUPPORTED_CHARSET, UNSUPPORTED_CHARSET_INDEX); - - charsets = Collections.unmodifiableMap(charsetsMap); - } - - /** - * Compares charsets. Returns a negative integer, zero, or a positive - * integer as the first charset is worse than, equal to, or better than - * the second. - *

- * Charsets are ordered according to the following rules: - *

    - *
  • All unsupported charsets are equal. - *
  • Any unsupported charset is worse than any supported charset. - *
  • Unicode charsets, such as "UTF-16", "UTF-8", "UTF-16BE" and - * "UTF-16LE", are considered best. - *
  • After them, platform default charset is selected. - *
  • "US-ASCII" is the worst of supported charsets. - *
  • For all other supported charsets, the lexicographically less - * one is considered the better. - *
- * - * @param charset1 the first charset to be compared - * @param charset2 the second charset to be compared. - * @return a negative integer, zero, or a positive integer as the - * first argument is worse, equal to, or better than the - * second. - */ - public int compare(String charset1, String charset2) { - charset1 = getEncoding(charset1); - charset2 = getEncoding(charset2); - - int comp = compareIndices(charsets, charset1, charset2, OTHER_CHARSET_INDEX); - - if (comp == 0) { - return charset2.compareTo(charset1); - } - - return comp; - } - - /** - * Returns encoding for the specified charset according to the - * following rules: - *
    - *
  • If the charset is null, then null will - * be returned. - *
  • Iff the charset specifies an encoding unsupported by this JRE, - * UNSUPPORTED_CHARSET will be returned. - *
  • If the charset specifies an alias name, the corresponding - * canonical name will be returned iff the charset is a known - * Unicode, ASCII, or default charset. - *
- * - * @param charset the charset. - * @return an encoding for this charset. - */ - static String getEncoding(String charset) { - if (charset == null) { - return null; - } else if (!isEncodingSupported(charset)) { - return UNSUPPORTED_CHARSET; - } else { - // Only convert to canonical form if the charset is one - // of the charsets explicitly listed in the known charsets - // map. This will happen only for Unicode, ASCII, or default - // charsets. - String canonicalName = canonicalName(charset); - return (charsets.containsKey(canonicalName)) - ? canonicalName - : charset; - } - } - } - - /** - * An IndexedComparator which compares two DataFlavors. For text flavors, - * the comparison follows the rules outlined in - * DataFlavor.selectBestTextFlavor. For non-text flavors, unknown - * application MIME types are preferred, followed by known - * application/x-java-* MIME types. Unknown application types are preferred - * because if the user provides his own data flavor, it will likely be the - * most descriptive one. For flavors which are otherwise equal, the - * flavors' string representation are compared in the alphabetical order. - */ - private static class DataFlavorComparator implements Comparator { - - static final DataFlavorComparator INSTANCE = new DataFlavorComparator(); - - private static final Map exactTypes; - private static final Map primaryTypes; - private static final Map, Integer> nonTextRepresentations; - private static final Map textTypes; - private static final Map, Integer> decodedTextRepresentations; - private static final Map, Integer> encodedTextRepresentations; - - private static final Integer UNKNOWN_OBJECT_LOSES = Integer.MIN_VALUE; - private static final Integer UNKNOWN_OBJECT_WINS = Integer.MAX_VALUE; - - static { - { - Map exactTypesMap = new HashMap<>(4, 1.0f); - - // application/x-java-* MIME types - exactTypesMap.put("application/x-java-file-list", 0); - exactTypesMap.put("application/x-java-serialized-object", 1); - exactTypesMap.put("application/x-java-jvm-local-objectref", 2); - exactTypesMap.put("application/x-java-remote-object", 3); - - exactTypes = Collections.unmodifiableMap(exactTypesMap); - } - - { - Map primaryTypesMap = new HashMap<>(1, 1.0f); - - primaryTypesMap.put("application", 0); - - primaryTypes = Collections.unmodifiableMap(primaryTypesMap); - } - - { - Map, Integer> nonTextRepresentationsMap = new HashMap<>(3, 1.0f); - - nonTextRepresentationsMap.put(java.io.InputStream.class, 0); - nonTextRepresentationsMap.put(java.io.Serializable.class, 1); - - nonTextRepresentationsMap.put(RMI.remoteClass(), 2); - - nonTextRepresentations = Collections.unmodifiableMap(nonTextRepresentationsMap); - } - - { - Map textTypesMap = new HashMap<>(16, 1.0f); - - // plain text - textTypesMap.put("text/plain", 0); - - // stringFlavor - textTypesMap.put("application/x-java-serialized-object", 1); - - // misc - textTypesMap.put("text/calendar", 2); - textTypesMap.put("text/css", 3); - textTypesMap.put("text/directory", 4); - textTypesMap.put("text/parityfec", 5); - textTypesMap.put("text/rfc822-headers", 6); - textTypesMap.put("text/t140", 7); - textTypesMap.put("text/tab-separated-values", 8); - textTypesMap.put("text/uri-list", 9); - - // enriched - textTypesMap.put("text/richtext", 10); - textTypesMap.put("text/enriched", 11); - textTypesMap.put("text/rtf", 12); - - // markup - textTypesMap.put("text/html", 13); - textTypesMap.put("text/xml", 14); - textTypesMap.put("text/sgml", 15); - - textTypes = Collections.unmodifiableMap(textTypesMap); - } - - { - Map, Integer> decodedTextRepresentationsMap = new HashMap<>(4, 1.0f); - - decodedTextRepresentationsMap.put(char[].class, 0); - decodedTextRepresentationsMap.put(CharBuffer.class, 1); - decodedTextRepresentationsMap.put(String.class, 2); - decodedTextRepresentationsMap.put(Reader.class, 3); - - decodedTextRepresentations = - Collections.unmodifiableMap(decodedTextRepresentationsMap); - } - - { - Map, Integer> encodedTextRepresentationsMap = new HashMap<>(3, 1.0f); - - encodedTextRepresentationsMap.put(byte[].class, 0); - encodedTextRepresentationsMap.put(ByteBuffer.class, 1); - encodedTextRepresentationsMap.put(InputStream.class, 2); - - encodedTextRepresentations = - Collections.unmodifiableMap(encodedTextRepresentationsMap); - } - } - - - public int compare(DataFlavor flavor1, DataFlavor flavor2) { - if (flavor1.equals(flavor2)) { - return 0; - } - - int comp; - - String primaryType1 = flavor1.getPrimaryType(); - String subType1 = flavor1.getSubType(); - String mimeType1 = primaryType1 + "/" + subType1; - Class class1 = flavor1.getRepresentationClass(); - - String primaryType2 = flavor2.getPrimaryType(); - String subType2 = flavor2.getSubType(); - String mimeType2 = primaryType2 + "/" + subType2; - Class class2 = flavor2.getRepresentationClass(); - - if (flavor1.isFlavorTextType() && flavor2.isFlavorTextType()) { - // First, compare MIME types - comp = compareIndices(textTypes, mimeType1, mimeType2, UNKNOWN_OBJECT_LOSES); - if (comp != 0) { - return comp; - } - - // Only need to test one flavor because they both have the - // same MIME type. Also don't need to worry about accidentally - // passing stringFlavor because either - // 1. Both flavors are stringFlavor, in which case the - // equality test at the top of the function succeeded. - // 2. Only one flavor is stringFlavor, in which case the MIME - // type comparison returned a non-zero value. - if (doesSubtypeSupportCharset(flavor1)) { - // Next, prefer the decoded text representations of Reader, - // String, CharBuffer, and [C, in that order. - comp = compareIndices(decodedTextRepresentations, class1, - class2, UNKNOWN_OBJECT_LOSES); - if (comp != 0) { - return comp; - } - - // Next, compare charsets - comp = CharsetComparator.INSTANCE.compare(getTextCharset(flavor1), - getTextCharset(flavor2)); - if (comp != 0) { - return comp; - } - } - - // Finally, prefer the encoded text representations of - // InputStream, ByteBuffer, and [B, in that order. - comp = compareIndices(encodedTextRepresentations, class1, - class2, UNKNOWN_OBJECT_LOSES); - if (comp != 0) { - return comp; - } - } else { - // First, prefer application types. - comp = compareIndices(primaryTypes, primaryType1, primaryType2, - UNKNOWN_OBJECT_LOSES); - if (comp != 0) { - return comp; - } - - // Next prefer text types - if (flavor1.isFlavorTextType()) { - return 1; - } - - if (flavor2.isFlavorTextType()) { - return -1; - } - - // Next, look for application/x-java-* types. Prefer unknown - // MIME types because if the user provides his own data flavor, - // it will likely be the most descriptive one. - comp = compareIndices(exactTypes, mimeType1, mimeType2, - UNKNOWN_OBJECT_WINS); - if (comp != 0) { - return comp; - } - - // Finally, prefer the representation classes of Remote, - // Serializable, and InputStream, in that order. - comp = compareIndices(nonTextRepresentations, class1, class2, - UNKNOWN_OBJECT_LOSES); - if (comp != 0) { - return comp; - } - } - - // The flavours are not equal but still not distinguishable. - // Compare String representations in alphabetical order - return flavor1.getMimeType().compareTo(flavor2.getMimeType()); - } - } - - /* - * Given the Map that maps objects to Integer indices and a boolean value, - * this Comparator imposes a direct or reverse order on set of objects. - *

- * If the specified boolean value is SELECT_BEST, the Comparator imposes the - * direct index-based order: an object A is greater than an object B if and - * only if the index of A is greater than the index of B. An object that - * doesn't have an associated index is less or equal than any other object. - *

- * If the specified boolean value is SELECT_WORST, the Comparator imposes the - * reverse index-based order: an object A is greater than an object B if and - * only if A is less than B with the direct index-based order. - */ - private static class IndexOrderComparator implements Comparator { - private final Map indexMap; - private static final Integer FALLBACK_INDEX = Integer.MIN_VALUE; - - public IndexOrderComparator(Map indexMap) { - this.indexMap = indexMap; - } - - public int compare(Long obj1, Long obj2) { - return compareIndices(indexMap, obj1, obj2, FALLBACK_INDEX); - } - } - - private static class TextFlavorComparator extends DataFlavorComparator { - - static final TextFlavorComparator INSTANCE = new TextFlavorComparator(); - /** - * Compares two DataFlavor objects. Returns a negative - * integer, zero, or a positive integer as the first - * DataFlavor is worse than, equal to, or better than the - * second. - *

- * DataFlavors are ordered according to the rules outlined - * for selectBestTextFlavor. - * - * @param flavor1 the first DataFlavor to be compared - * @param flavor2 the second DataFlavor to be compared - * @return a negative integer, zero, or a positive integer as the first - * argument is worse, equal to, or better than the second - * @throws ClassCastException if either of the arguments is not an - * instance of DataFlavor - * @throws NullPointerException if either of the arguments is - * null - * - * @see java.awt.datatransfer.DataFlavor#selectBestTextFlavor - */ - public int compare(DataFlavor flavor1, DataFlavor flavor2) { - if (flavor1.isFlavorTextType()) { - if (flavor2.isFlavorTextType()) { - return super.compare(flavor1, flavor2); - } else { - return 1; - } - } else if (flavor2.isFlavorTextType()) { - return -1; - } else { - return 0; - } - } - } - - /** - * A fallback implementation of {@link sun.datatransfer.DesktopDatatransferService} - * used if there is no desktop. - */ - private static final class DefaultDesktopDatatransferService implements DesktopDatatransferService { - static final DesktopDatatransferService INSTANCE = getDesktopService(); - - private static DesktopDatatransferService getDesktopService() { - ServiceLoader loader = - ServiceLoader.load(DesktopDatatransferService.class, null); - Iterator iterator = loader.iterator(); - if (iterator.hasNext()) { - return iterator.next(); - } else { - return new DefaultDesktopDatatransferService(); - } - } - - /** - * System singleton FlavorTable. - * Only used if there is no desktop - * to provide an appropriate FlavorMap. - */ - private volatile FlavorMap flavorMap; - - @Override - public void invokeOnEventThread(Runnable r) { - r.run(); - } - - @Override - public String getDefaultUnicodeEncoding() { - return StandardCharsets.UTF_8.name(); - } - - @Override - public FlavorMap getFlavorMap(Supplier supplier) { - FlavorMap map = flavorMap; - if (map == null) { - synchronized (this) { - map = flavorMap; - if (map == null) { - flavorMap = map = supplier.get(); - } - } - } - return map; - } - - @Override - public boolean isDesktopPresent() { - return false; - } - - @Override - public LinkedHashSet getPlatformMappingsForNative(String nat) { - return new LinkedHashSet<>(); - } - - @Override - public LinkedHashSet getPlatformMappingsForFlavor(DataFlavor df) { - return new LinkedHashSet<>(); - } - - @Override - public void registerTextFlavorProperties(String nat, String charset, - String eoln, String terminators) { - // Not needed if desktop module is absent - } - } - - public static DesktopDatatransferService getDesktopService() { - return DefaultDesktopDatatransferService.INSTANCE; - } - - /** - * A class that provides access to java.rmi.Remote and java.rmi.MarshalledObject - * without creating a static dependency. - */ - public static class RMI { - private static final Class remoteClass = getClass("java.rmi.Remote"); - private static final Class marshallObjectClass = getClass("java.rmi.MarshalledObject"); - private static final Constructor marshallCtor = getConstructor(marshallObjectClass, Object.class); - private static final Method marshallGet = getMethod(marshallObjectClass, "get"); - - private static Class getClass(String name) { - try { - return Class.forName(name, true, null); - } catch (ClassNotFoundException e) { - return null; - } - } - - private static Constructor getConstructor(Class c, Class... types) { - try { - return (c == null) ? null : c.getDeclaredConstructor(types); - } catch (NoSuchMethodException x) { - throw new AssertionError(x); - } - } - - private static Method getMethod(Class c, String name, Class... types) { - try { - return (c == null) ? null : c.getMethod(name, types); - } catch (NoSuchMethodException e) { - throw new AssertionError(e); - } - } - - /** - * Returns java.rmi.Remote.class if RMI is present; otherwise {@code null}. - */ - static Class remoteClass() { - return remoteClass; - } - - /** - * Returns {@code true} if the given class is java.rmi.Remote. - */ - public static boolean isRemote(Class c) { - return (remoteClass != null) && remoteClass.isAssignableFrom(c); - } - - /** - * Returns a new MarshalledObject containing the serialized representation - * of the given object. - */ - public static Object newMarshalledObject(Object obj) throws IOException { - try { - return marshallCtor == null ? null : marshallCtor.newInstance(obj); - } catch (InstantiationException | IllegalAccessException x) { - throw new AssertionError(x); - } catch (InvocationTargetException x) { - Throwable cause = x.getCause(); - if (cause instanceof IOException) - throw (IOException) cause; - throw new AssertionError(x); - } - } - - /** - * Returns a new copy of the contained marshalled object. - */ - public static Object getMarshalledObject(Object obj) - throws IOException, ClassNotFoundException { - try { - return marshallGet == null ? null : marshallGet.invoke(obj); - } catch (IllegalAccessException x) { - throw new AssertionError(x); - } catch (InvocationTargetException x) { - Throwable cause = x.getCause(); - if (cause instanceof IOException) - throw (IOException) cause; - if (cause instanceof ClassNotFoundException) - throw (ClassNotFoundException) cause; - throw new AssertionError(x); - } - } - - } -} --- /dev/null 2015-01-13 17:35:24.000000000 +0400 +++ new/src/java.datatransfer/share/classes/sun/datatransfer/DataFlavorUtil.java 2015-01-13 17:35:19.655199600 +0400 @@ -0,0 +1,841 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.datatransfer; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.FlavorMap; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.StandardCharsets; +import java.nio.charset.UnsupportedCharsetException; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.function.Supplier; + + +/** + * Utility class with different datatransfer helper functions + * + * @see 1.9 + */ +public class DataFlavorUtil { + + private DataFlavorUtil() { + // Avoid instantiation + } + + private static Comparator getCharsetComparator() { + return CharsetComparator.INSTANCE; + } + + public static Comparator getDataFlavorComparator() { + return DataFlavorComparator.INSTANCE; + } + + public static Comparator getIndexOrderComparator(Map indexMap) { + return new IndexOrderComparator(indexMap); + } + + public static Comparator getTextFlavorComparator() { + return TextFlavorComparator.INSTANCE; + } + + /** + * Tracks whether a particular text/* MIME type supports the charset + * parameter. The Map is initialized with all of the standard MIME types + * listed in the DataFlavor.selectBestTextFlavor method comment. Additional + * entries may be added during the life of the JRE for text/ types. + */ + private static final Map textMIMESubtypeCharsetSupport; + + static { + Map tempMap = new HashMap<>(17); + tempMap.put("sgml", Boolean.TRUE); + tempMap.put("xml", Boolean.TRUE); + tempMap.put("html", Boolean.TRUE); + tempMap.put("enriched", Boolean.TRUE); + tempMap.put("richtext", Boolean.TRUE); + tempMap.put("uri-list", Boolean.TRUE); + tempMap.put("directory", Boolean.TRUE); + tempMap.put("css", Boolean.TRUE); + tempMap.put("calendar", Boolean.TRUE); + tempMap.put("plain", Boolean.TRUE); + tempMap.put("rtf", Boolean.FALSE); + tempMap.put("tab-separated-values", Boolean.FALSE); + tempMap.put("t140", Boolean.FALSE); + tempMap.put("rfc822-headers", Boolean.FALSE); + tempMap.put("parityfec", Boolean.FALSE); + textMIMESubtypeCharsetSupport = Collections.synchronizedMap(tempMap); + } + + /** + * Lazy initialization of Standard Encodings. + */ + private static class StandardEncodingsHolder { + private static final SortedSet standardEncodings = load(); + + private static SortedSet load() { + final SortedSet tempSet = new TreeSet<>(getCharsetComparator().reversed()); + tempSet.add("US-ASCII"); + tempSet.add("ISO-8859-1"); + tempSet.add("UTF-8"); + tempSet.add("UTF-16BE"); + tempSet.add("UTF-16LE"); + tempSet.add("UTF-16"); + tempSet.add(Charset.defaultCharset().name()); + return Collections.unmodifiableSortedSet(tempSet); + } + } + + /** + * Returns a {@code SortedSet} of Strings which are a total order of the standard + * character sets supported by the JRE. The ordering follows the same principles as + * {@link java.awt.datatransfer.DataFlavor#selectBestTextFlavor(java.awt.datatransfer.DataFlavor[])}. + * So as to avoid loading all available character converters, optional, non-standard, + * character sets are not included. + */ + public static Set standardEncodings() { + return StandardEncodingsHolder.standardEncodings; + } + + /** + * Converts an arbitrary text encoding to its canonical name. + */ + public static String canonicalName(String encoding) { + if (encoding == null) { + return null; + } + try { + return Charset.forName(encoding).name(); + } catch (IllegalCharsetNameException icne) { + return encoding; + } catch (UnsupportedCharsetException uce) { + return encoding; + } + } + + /** + * Tests only whether the flavor's MIME type supports the charset + * parameter. Must only be called for flavors with a primary type of + * "text". + */ + public static boolean doesSubtypeSupportCharset(DataFlavor flavor) { + String subType = flavor.getSubType(); + if (subType == null) { + return false; + } + + Boolean support = textMIMESubtypeCharsetSupport.get(subType); + + if (support != null) { + return support; + } + + boolean ret_val = (flavor.getParameter("charset") != null); + textMIMESubtypeCharsetSupport.put(subType, ret_val); + return ret_val; + } + public static boolean doesSubtypeSupportCharset(String subType, + String charset) + { + Boolean support = textMIMESubtypeCharsetSupport.get(subType); + + if (support != null) { + return support; + } + + boolean ret_val = (charset != null); + textMIMESubtypeCharsetSupport.put(subType, ret_val); + return ret_val; + } + + + /** + * Returns whether this flavor is a text type which supports the + * 'charset' parameter. + */ + public static boolean isFlavorCharsetTextType(DataFlavor flavor) { + // Although stringFlavor doesn't actually support the charset + // parameter (because its primary MIME type is not "text"), it should + // be treated as though it does. stringFlavor is semantically + // equivalent to "text/plain" data. + if (DataFlavor.stringFlavor.equals(flavor)) { + return true; + } + + if (!"text".equals(flavor.getPrimaryType()) || + !doesSubtypeSupportCharset(flavor)) + { + return false; + } + + Class rep_class = flavor.getRepresentationClass(); + + if (flavor.isRepresentationClassReader() || + String.class.equals(rep_class) || + flavor.isRepresentationClassCharBuffer() || + char[].class.equals(rep_class)) + { + return true; + } + + if (!(flavor.isRepresentationClassInputStream() || + flavor.isRepresentationClassByteBuffer() || + byte[].class.equals(rep_class))) { + return false; + } + + String charset = flavor.getParameter("charset"); + + // null equals default encoding which is always supported + return (charset == null) || isEncodingSupported(charset); + } + + /** + * Returns whether this flavor is a text type which does not support the + * 'charset' parameter. + */ + public static boolean isFlavorNoncharsetTextType(DataFlavor flavor) { + if (!"text".equals(flavor.getPrimaryType()) || doesSubtypeSupportCharset(flavor)) { + return false; + } + + return (flavor.isRepresentationClassInputStream() || + flavor.isRepresentationClassByteBuffer() || + byte[].class.equals(flavor.getRepresentationClass())); + } + + /** + * If the specified flavor is a text flavor which supports the "charset" + * parameter, then this method returns that parameter, or the default + * charset if no such parameter was specified at construction. For non- + * text DataFlavors, and for non-charset text flavors, this method returns + * null. + */ + public static String getTextCharset(DataFlavor flavor) { + if (!isFlavorCharsetTextType(flavor)) { + return null; + } + + String encoding = flavor.getParameter("charset"); + + return (encoding != null) ? encoding : Charset.defaultCharset().name(); + } + + /** + * Determines whether this JRE can both encode and decode text in the + * specified encoding. + */ + private static boolean isEncodingSupported(String encoding) { + if (encoding == null) { + return false; + } + try { + return Charset.isSupported(encoding); + } catch (IllegalCharsetNameException icne) { + return false; + } + } + + /** + * Helper method to compare two objects by their Integer indices in the + * given map. If the map doesn't contain an entry for either of the + * objects, the fallback index will be used for the object instead. + * + * @param indexMap the map which maps objects into Integer indexes. + * @param obj1 the first object to be compared. + * @param obj2 the second object to be compared. + * @param fallbackIndex the Integer to be used as a fallback index. + * @return a negative integer, zero, or a positive integer as the + * first object is mapped to a less, equal to, or greater + * index than the second. + */ + static int compareIndices(Map indexMap, + T obj1, T obj2, + Integer fallbackIndex) { + Integer index1 = indexMap.getOrDefault(obj1, fallbackIndex); + Integer index2 = indexMap.getOrDefault(obj2, fallbackIndex); + return index1.compareTo(index2); + } + + /** + * An IndexedComparator which compares two String charsets. The comparison + * follows the rules outlined in DataFlavor.selectBestTextFlavor. In order + * to ensure that non-Unicode, non-ASCII, non-default charsets are sorted + * in alphabetical order, charsets are not automatically converted to their + * canonical forms. + */ + private static class CharsetComparator implements Comparator { + static final CharsetComparator INSTANCE = new CharsetComparator(); + + private static final Map charsets; + + private static final Integer DEFAULT_CHARSET_INDEX = 2; + private static final Integer OTHER_CHARSET_INDEX = 1; + private static final Integer WORST_CHARSET_INDEX = 0; + private static final Integer UNSUPPORTED_CHARSET_INDEX = Integer.MIN_VALUE; + + private static final String UNSUPPORTED_CHARSET = "UNSUPPORTED"; + + static { + Map charsetsMap = new HashMap<>(8, 1.0f); + + // we prefer Unicode charsets + charsetsMap.put(canonicalName("UTF-16LE"), 4); + charsetsMap.put(canonicalName("UTF-16BE"), 5); + charsetsMap.put(canonicalName("UTF-8"), 6); + charsetsMap.put(canonicalName("UTF-16"), 7); + + // US-ASCII is the worst charset supported + charsetsMap.put(canonicalName("US-ASCII"), WORST_CHARSET_INDEX); + + charsetsMap.putIfAbsent(Charset.defaultCharset().name(), DEFAULT_CHARSET_INDEX); + + charsetsMap.put(UNSUPPORTED_CHARSET, UNSUPPORTED_CHARSET_INDEX); + + charsets = Collections.unmodifiableMap(charsetsMap); + } + + /** + * Compares charsets. Returns a negative integer, zero, or a positive + * integer as the first charset is worse than, equal to, or better than + * the second. + *

+ * Charsets are ordered according to the following rules: + *

    + *
  • All unsupported charsets are equal. + *
  • Any unsupported charset is worse than any supported charset. + *
  • Unicode charsets, such as "UTF-16", "UTF-8", "UTF-16BE" and + * "UTF-16LE", are considered best. + *
  • After them, platform default charset is selected. + *
  • "US-ASCII" is the worst of supported charsets. + *
  • For all other supported charsets, the lexicographically less + * one is considered the better. + *
+ * + * @param charset1 the first charset to be compared + * @param charset2 the second charset to be compared. + * @return a negative integer, zero, or a positive integer as the + * first argument is worse, equal to, or better than the + * second. + */ + public int compare(String charset1, String charset2) { + charset1 = getEncoding(charset1); + charset2 = getEncoding(charset2); + + int comp = compareIndices(charsets, charset1, charset2, OTHER_CHARSET_INDEX); + + if (comp == 0) { + return charset2.compareTo(charset1); + } + + return comp; + } + + /** + * Returns encoding for the specified charset according to the + * following rules: + *
    + *
  • If the charset is null, then null will + * be returned. + *
  • Iff the charset specifies an encoding unsupported by this JRE, + * UNSUPPORTED_CHARSET will be returned. + *
  • If the charset specifies an alias name, the corresponding + * canonical name will be returned iff the charset is a known + * Unicode, ASCII, or default charset. + *
+ * + * @param charset the charset. + * @return an encoding for this charset. + */ + static String getEncoding(String charset) { + if (charset == null) { + return null; + } else if (!isEncodingSupported(charset)) { + return UNSUPPORTED_CHARSET; + } else { + // Only convert to canonical form if the charset is one + // of the charsets explicitly listed in the known charsets + // map. This will happen only for Unicode, ASCII, or default + // charsets. + String canonicalName = canonicalName(charset); + return (charsets.containsKey(canonicalName)) + ? canonicalName + : charset; + } + } + } + + /** + * An IndexedComparator which compares two DataFlavors. For text flavors, + * the comparison follows the rules outlined in + * DataFlavor.selectBestTextFlavor. For non-text flavors, unknown + * application MIME types are preferred, followed by known + * application/x-java-* MIME types. Unknown application types are preferred + * because if the user provides his own data flavor, it will likely be the + * most descriptive one. For flavors which are otherwise equal, the + * flavors' string representation are compared in the alphabetical order. + */ + private static class DataFlavorComparator implements Comparator { + + static final DataFlavorComparator INSTANCE = new DataFlavorComparator(); + + private static final Map exactTypes; + private static final Map primaryTypes; + private static final Map, Integer> nonTextRepresentations; + private static final Map textTypes; + private static final Map, Integer> decodedTextRepresentations; + private static final Map, Integer> encodedTextRepresentations; + + private static final Integer UNKNOWN_OBJECT_LOSES = Integer.MIN_VALUE; + private static final Integer UNKNOWN_OBJECT_WINS = Integer.MAX_VALUE; + + static { + { + Map exactTypesMap = new HashMap<>(4, 1.0f); + + // application/x-java-* MIME types + exactTypesMap.put("application/x-java-file-list", 0); + exactTypesMap.put("application/x-java-serialized-object", 1); + exactTypesMap.put("application/x-java-jvm-local-objectref", 2); + exactTypesMap.put("application/x-java-remote-object", 3); + + exactTypes = Collections.unmodifiableMap(exactTypesMap); + } + + { + Map primaryTypesMap = new HashMap<>(1, 1.0f); + + primaryTypesMap.put("application", 0); + + primaryTypes = Collections.unmodifiableMap(primaryTypesMap); + } + + { + Map, Integer> nonTextRepresentationsMap = new HashMap<>(3, 1.0f); + + nonTextRepresentationsMap.put(java.io.InputStream.class, 0); + nonTextRepresentationsMap.put(java.io.Serializable.class, 1); + + nonTextRepresentationsMap.put(RMI.remoteClass(), 2); + + nonTextRepresentations = Collections.unmodifiableMap(nonTextRepresentationsMap); + } + + { + Map textTypesMap = new HashMap<>(16, 1.0f); + + // plain text + textTypesMap.put("text/plain", 0); + + // stringFlavor + textTypesMap.put("application/x-java-serialized-object", 1); + + // misc + textTypesMap.put("text/calendar", 2); + textTypesMap.put("text/css", 3); + textTypesMap.put("text/directory", 4); + textTypesMap.put("text/parityfec", 5); + textTypesMap.put("text/rfc822-headers", 6); + textTypesMap.put("text/t140", 7); + textTypesMap.put("text/tab-separated-values", 8); + textTypesMap.put("text/uri-list", 9); + + // enriched + textTypesMap.put("text/richtext", 10); + textTypesMap.put("text/enriched", 11); + textTypesMap.put("text/rtf", 12); + + // markup + textTypesMap.put("text/html", 13); + textTypesMap.put("text/xml", 14); + textTypesMap.put("text/sgml", 15); + + textTypes = Collections.unmodifiableMap(textTypesMap); + } + + { + Map, Integer> decodedTextRepresentationsMap = new HashMap<>(4, 1.0f); + + decodedTextRepresentationsMap.put(char[].class, 0); + decodedTextRepresentationsMap.put(CharBuffer.class, 1); + decodedTextRepresentationsMap.put(String.class, 2); + decodedTextRepresentationsMap.put(Reader.class, 3); + + decodedTextRepresentations = + Collections.unmodifiableMap(decodedTextRepresentationsMap); + } + + { + Map, Integer> encodedTextRepresentationsMap = new HashMap<>(3, 1.0f); + + encodedTextRepresentationsMap.put(byte[].class, 0); + encodedTextRepresentationsMap.put(ByteBuffer.class, 1); + encodedTextRepresentationsMap.put(InputStream.class, 2); + + encodedTextRepresentations = + Collections.unmodifiableMap(encodedTextRepresentationsMap); + } + } + + + public int compare(DataFlavor flavor1, DataFlavor flavor2) { + if (flavor1.equals(flavor2)) { + return 0; + } + + int comp; + + String primaryType1 = flavor1.getPrimaryType(); + String subType1 = flavor1.getSubType(); + String mimeType1 = primaryType1 + "/" + subType1; + Class class1 = flavor1.getRepresentationClass(); + + String primaryType2 = flavor2.getPrimaryType(); + String subType2 = flavor2.getSubType(); + String mimeType2 = primaryType2 + "/" + subType2; + Class class2 = flavor2.getRepresentationClass(); + + if (flavor1.isFlavorTextType() && flavor2.isFlavorTextType()) { + // First, compare MIME types + comp = compareIndices(textTypes, mimeType1, mimeType2, UNKNOWN_OBJECT_LOSES); + if (comp != 0) { + return comp; + } + + // Only need to test one flavor because they both have the + // same MIME type. Also don't need to worry about accidentally + // passing stringFlavor because either + // 1. Both flavors are stringFlavor, in which case the + // equality test at the top of the function succeeded. + // 2. Only one flavor is stringFlavor, in which case the MIME + // type comparison returned a non-zero value. + if (doesSubtypeSupportCharset(flavor1)) { + // Next, prefer the decoded text representations of Reader, + // String, CharBuffer, and [C, in that order. + comp = compareIndices(decodedTextRepresentations, class1, + class2, UNKNOWN_OBJECT_LOSES); + if (comp != 0) { + return comp; + } + + // Next, compare charsets + comp = CharsetComparator.INSTANCE.compare(getTextCharset(flavor1), + getTextCharset(flavor2)); + if (comp != 0) { + return comp; + } + } + + // Finally, prefer the encoded text representations of + // InputStream, ByteBuffer, and [B, in that order. + comp = compareIndices(encodedTextRepresentations, class1, + class2, UNKNOWN_OBJECT_LOSES); + if (comp != 0) { + return comp; + } + } else { + // First, prefer application types. + comp = compareIndices(primaryTypes, primaryType1, primaryType2, + UNKNOWN_OBJECT_LOSES); + if (comp != 0) { + return comp; + } + + // Next prefer text types + if (flavor1.isFlavorTextType()) { + return 1; + } + + if (flavor2.isFlavorTextType()) { + return -1; + } + + // Next, look for application/x-java-* types. Prefer unknown + // MIME types because if the user provides his own data flavor, + // it will likely be the most descriptive one. + comp = compareIndices(exactTypes, mimeType1, mimeType2, + UNKNOWN_OBJECT_WINS); + if (comp != 0) { + return comp; + } + + // Finally, prefer the representation classes of Remote, + // Serializable, and InputStream, in that order. + comp = compareIndices(nonTextRepresentations, class1, class2, + UNKNOWN_OBJECT_LOSES); + if (comp != 0) { + return comp; + } + } + + // The flavours are not equal but still not distinguishable. + // Compare String representations in alphabetical order + return flavor1.getMimeType().compareTo(flavor2.getMimeType()); + } + } + + /* + * Given the Map that maps objects to Integer indices and a boolean value, + * this Comparator imposes a direct or reverse order on set of objects. + *

+ * If the specified boolean value is SELECT_BEST, the Comparator imposes the + * direct index-based order: an object A is greater than an object B if and + * only if the index of A is greater than the index of B. An object that + * doesn't have an associated index is less or equal than any other object. + *

+ * If the specified boolean value is SELECT_WORST, the Comparator imposes the + * reverse index-based order: an object A is greater than an object B if and + * only if A is less than B with the direct index-based order. + */ + private static class IndexOrderComparator implements Comparator { + private final Map indexMap; + private static final Integer FALLBACK_INDEX = Integer.MIN_VALUE; + + public IndexOrderComparator(Map indexMap) { + this.indexMap = indexMap; + } + + public int compare(Long obj1, Long obj2) { + return compareIndices(indexMap, obj1, obj2, FALLBACK_INDEX); + } + } + + private static class TextFlavorComparator extends DataFlavorComparator { + + static final TextFlavorComparator INSTANCE = new TextFlavorComparator(); + /** + * Compares two DataFlavor objects. Returns a negative + * integer, zero, or a positive integer as the first + * DataFlavor is worse than, equal to, or better than the + * second. + *

+ * DataFlavors are ordered according to the rules outlined + * for selectBestTextFlavor. + * + * @param flavor1 the first DataFlavor to be compared + * @param flavor2 the second DataFlavor to be compared + * @return a negative integer, zero, or a positive integer as the first + * argument is worse, equal to, or better than the second + * @throws ClassCastException if either of the arguments is not an + * instance of DataFlavor + * @throws NullPointerException if either of the arguments is + * null + * + * @see java.awt.datatransfer.DataFlavor#selectBestTextFlavor + */ + public int compare(DataFlavor flavor1, DataFlavor flavor2) { + if (flavor1.isFlavorTextType()) { + if (flavor2.isFlavorTextType()) { + return super.compare(flavor1, flavor2); + } else { + return 1; + } + } else if (flavor2.isFlavorTextType()) { + return -1; + } else { + return 0; + } + } + } + + /** + * A fallback implementation of {@link sun.datatransfer.DesktopDatatransferService} + * used if there is no desktop. + */ + private static final class DefaultDesktopDatatransferService implements DesktopDatatransferService { + static final DesktopDatatransferService INSTANCE = getDesktopService(); + + private static DesktopDatatransferService getDesktopService() { + ServiceLoader loader = + ServiceLoader.load(DesktopDatatransferService.class, null); + Iterator iterator = loader.iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } else { + return new DefaultDesktopDatatransferService(); + } + } + + /** + * System singleton FlavorTable. + * Only used if there is no desktop + * to provide an appropriate FlavorMap. + */ + private volatile FlavorMap flavorMap; + + @Override + public void invokeOnEventThread(Runnable r) { + r.run(); + } + + @Override + public String getDefaultUnicodeEncoding() { + return StandardCharsets.UTF_8.name(); + } + + @Override + public FlavorMap getFlavorMap(Supplier supplier) { + FlavorMap map = flavorMap; + if (map == null) { + synchronized (this) { + map = flavorMap; + if (map == null) { + flavorMap = map = supplier.get(); + } + } + } + return map; + } + + @Override + public boolean isDesktopPresent() { + return false; + } + + @Override + public LinkedHashSet getPlatformMappingsForNative(String nat) { + return new LinkedHashSet<>(); + } + + @Override + public LinkedHashSet getPlatformMappingsForFlavor(DataFlavor df) { + return new LinkedHashSet<>(); + } + + @Override + public void registerTextFlavorProperties(String nat, String charset, + String eoln, String terminators) { + // Not needed if desktop module is absent + } + } + + public static DesktopDatatransferService getDesktopService() { + return DefaultDesktopDatatransferService.INSTANCE; + } + + /** + * A class that provides access to java.rmi.Remote and java.rmi.MarshalledObject + * without creating a static dependency. + */ + public static class RMI { + private static final Class remoteClass = getClass("java.rmi.Remote"); + private static final Class marshallObjectClass = getClass("java.rmi.MarshalledObject"); + private static final Constructor marshallCtor = getConstructor(marshallObjectClass, Object.class); + private static final Method marshallGet = getMethod(marshallObjectClass, "get"); + + private static Class getClass(String name) { + try { + return Class.forName(name, true, null); + } catch (ClassNotFoundException e) { + return null; + } + } + + private static Constructor getConstructor(Class c, Class... types) { + try { + return (c == null) ? null : c.getDeclaredConstructor(types); + } catch (NoSuchMethodException x) { + throw new AssertionError(x); + } + } + + private static Method getMethod(Class c, String name, Class... types) { + try { + return (c == null) ? null : c.getMethod(name, types); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + /** + * Returns java.rmi.Remote.class if RMI is present; otherwise {@code null}. + */ + static Class remoteClass() { + return remoteClass; + } + + /** + * Returns {@code true} if the given class is java.rmi.Remote. + */ + public static boolean isRemote(Class c) { + return (remoteClass != null) && remoteClass.isAssignableFrom(c); + } + + /** + * Returns a new MarshalledObject containing the serialized representation + * of the given object. + */ + public static Object newMarshalledObject(Object obj) throws IOException { + try { + return marshallCtor == null ? null : marshallCtor.newInstance(obj); + } catch (InstantiationException | IllegalAccessException x) { + throw new AssertionError(x); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + if (cause instanceof IOException) + throw (IOException) cause; + throw new AssertionError(x); + } + } + + /** + * Returns a new copy of the contained marshalled object. + */ + public static Object getMarshalledObject(Object obj) + throws IOException, ClassNotFoundException { + try { + return marshallGet == null ? null : marshallGet.invoke(obj); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + if (cause instanceof IOException) + throw (IOException) cause; + if (cause instanceof ClassNotFoundException) + throw (ClassNotFoundException) cause; + throw new AssertionError(x); + } + } + + } +} --- old/src/java.desktop/share/classes/sun/datatransfer/DesktopDatatransferService.java 2015-01-13 17:35:31.187859300 +0400 +++ /dev/null 2015-01-13 17:35:32.000000000 +0400 @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.datatransfer; - -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.FlavorMap; -import java.util.LinkedHashSet; -import java.util.function.Supplier; - -/** - * Contains services which desktop provides to the datatransfer system - * to enrich it's functionality - * - * @author Petr Pchelko - * @since 1.9 - */ -public interface DesktopDatatransferService { - - /** - * If desktop is present - invokes a {@code Runnable} on - * the event dispatch thread. Otherwise invokes a {@code run()} - * method directly. - * - * @param r a {@code Runnable} to invoke - */ - void invokeOnEventThread(Runnable r); - - /** - * Get a platform-dependent default unicode encoding to use in - * datatransfer system. - * - * @return default unicode encoding - */ - String getDefaultUnicodeEncoding(); - - /** - * Takes an appropriate {@code FlavorMap} from the desktop. - * If no appropriate table is found - uses a provided supplier to - * instantiate a table. If the desktop is absent - creates and returns - * a system singleton. - * - * @param supplier a constructor that should be used to create a new instance of - * the {@code FlavorMap} - * @return a {@code FlavorMap} - */ - FlavorMap getFlavorMap(Supplier supplier); - - /** - * Checks if desktop is present - * - * @return {@code true} is the desktop is present - */ - boolean isDesktopPresent(); - - /** - * Returns platform-specific mappings for the specified native format. - * If there are no platform-specific mappings for this native, the method - * returns an empty {@code Set} - * - * @param nat a native format to return flavors for - * @return set of platform-specific mappings for a native format - */ - LinkedHashSet getPlatformMappingsForNative(String nat); - - /** - * Returns platform-specific mappings for the specified flavor. - * If there are no platform-specific mappings for this flavor, the method - * returns an empty {@code Set} - * - * @param df {@code DataFlavor} to return mappings for - * @return set of platform-specific mappings for a {@code DataFlavor} - */ - LinkedHashSet getPlatformMappingsForFlavor(DataFlavor df); - - /** - * This method is called for text flavor mappings established while parsing - * the default flavor mappings file. It stores the "eoln" and "terminators" - * parameters which are not officially part of the MIME type. They are - * MIME parameters specific to the flavormap.properties file format. - */ - void registerTextFlavorProperties(String nat, String charset, - String eoln, String terminators); -} --- /dev/null 2015-01-13 17:35:32.000000000 +0400 +++ new/src/java.datatransfer/share/classes/sun/datatransfer/DesktopDatatransferService.java 2015-01-13 17:35:30.610826200 +0400 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.datatransfer; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.FlavorMap; +import java.util.LinkedHashSet; +import java.util.function.Supplier; + +/** + * Contains services which desktop provides to the datatransfer system + * to enrich it's functionality + * + * @author Petr Pchelko + * @since 1.9 + */ +public interface DesktopDatatransferService { + + /** + * If desktop is present - invokes a {@code Runnable} on + * the event dispatch thread. Otherwise invokes a {@code run()} + * method directly. + * + * @param r a {@code Runnable} to invoke + */ + void invokeOnEventThread(Runnable r); + + /** + * Get a platform-dependent default unicode encoding to use in + * datatransfer system. + * + * @return default unicode encoding + */ + String getDefaultUnicodeEncoding(); + + /** + * Takes an appropriate {@code FlavorMap} from the desktop. + * If no appropriate table is found - uses a provided supplier to + * instantiate a table. If the desktop is absent - creates and returns + * a system singleton. + * + * @param supplier a constructor that should be used to create a new instance of + * the {@code FlavorMap} + * @return a {@code FlavorMap} + */ + FlavorMap getFlavorMap(Supplier supplier); + + /** + * Checks if desktop is present + * + * @return {@code true} is the desktop is present + */ + boolean isDesktopPresent(); + + /** + * Returns platform-specific mappings for the specified native format. + * If there are no platform-specific mappings for this native, the method + * returns an empty {@code Set} + * + * @param nat a native format to return flavors for + * @return set of platform-specific mappings for a native format + */ + LinkedHashSet getPlatformMappingsForNative(String nat); + + /** + * Returns platform-specific mappings for the specified flavor. + * If there are no platform-specific mappings for this flavor, the method + * returns an empty {@code Set} + * + * @param df {@code DataFlavor} to return mappings for + * @return set of platform-specific mappings for a {@code DataFlavor} + */ + LinkedHashSet getPlatformMappingsForFlavor(DataFlavor df); + + /** + * This method is called for text flavor mappings established while parsing + * the default flavor mappings file. It stores the "eoln" and "terminators" + * parameters which are not officially part of the MIME type. They are + * MIME parameters specific to the flavormap.properties file format. + */ + void registerTextFlavorProperties(String nat, String charset, + String eoln, String terminators); +} --- old/src/java.desktop/unix/classes/sun/datatransfer/resources/flavormap.properties 2015-01-13 17:36:02.282637800 +0400 +++ /dev/null 2015-01-13 17:36:03.000000000 +0400 @@ -1,71 +0,0 @@ -# -# This properties file is used to initialize the default -# java.awt.datatransfer.SystemFlavorMap. It contains the X11 platform-specific, -# default mappings between common X11 selection atoms and platform-independent -# MIME type strings, which will be converted into -# java.awt.datatransfer.DataFlavors. -# -# The standard format is: -# -# =,, ... -# -# should be a string identifier that the native platform will -# recognize as a valid data format. should specify both a MIME -# primary type and a MIME subtype separated by a '/'. The MIME type may include -# parameters, where each parameter is a key/value pair separated by '=', and -# where each parameter to the MIME type is separated by a ';'. -# -# Because SystemFlavorMap implements FlavorTable, developers are free to -# duplicate DataFlavor values and set multiple values for a single native by -# separating them with ",". If a mapping contains a duplicate key or value, -# earlier mappings which included this key or value will be preferred. -# -# Mappings whose values specify DataFlavors with primary MIME types of -# "text", and which support the charset parameter, should specify the exact -# format in which the native platform expects the data. The "charset" -# parameter specifies the char to byte encoding, the "eoln" parameter -# specifies the end-of-line marker, and the "terminators" parameter specifies -# the number of terminating NUL bytes. Note that "eoln" and "terminators" -# are not standardized MIME type parameters. They are specific to this file -# format ONLY. They will not appear in any of the DataFlavors returned by the -# SystemFlavorMap at the Java level. -# -# If the "charset" parameter is omitted, or has zero length, the platform -# default encoding is assumed. If the "eoln" parameter is omitted, or has -# zero length, "\n" is assumed. If the "terminators" parameter is omitted, -# or has a value less than zero, zero is assumed. -# -# Upon initialization, the data transfer subsystem will record the specified -# details of the native text format, but the default SystemFlavorMap will -# present a large set of synthesized DataFlavors which map, in both -# directions, to the native. After receiving data from the application in one -# of the synthetic DataFlavors, the data transfer subsystem will transform -# the data stream into the format specified in this file before passing the -# transformed stream to the native system. -# -# Mappings whose values specify DataFlavors with primary MIME types of -# "text", but which do not support the charset parameter, will be treated as -# opaque, 8-bit data. They will not undergo any transformation process, and -# any "charset", "eoln", or "terminators" parameters specified in this file -# will be ignored. -# -# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of -# text flavors which support the charset parameter. - -UTF8_STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 - -# The COMPOUND_TEXT support for inter-client text transfer is disabled by -# default. The reason is that many native applications prefer this format over -# other native text formats, but are unable to decode the textual data in this -# format properly. This results in java-to-native text transfer failures. -# To enable the COMPOUND_TEXT support for this JRE installation uncomment -# the line below. - -# COMPOUND_TEXT=text/plain;charset=x-compound-text;eoln="\n";terminators=0 - -TEXT=text/plain;eoln="\n";terminators=0 -STRING=text/plain;charset=iso8859-1;eoln="\n";terminators=0 -FILE_NAME=application/x-java-file-list;class=java.util.List -text/uri-list=application/x-java-file-list;class=java.util.List -PNG=image/x-java-image;class=java.awt.Image -JFIF=image/x-java-image;class=java.awt.Image --- /dev/null 2015-01-13 17:36:04.000000000 +0400 +++ new/src/java.datatransfer/unix/classes/sun/datatransfer/resources/flavormap.properties 2015-01-13 17:35:53.725148300 +0400 @@ -0,0 +1,71 @@ +# +# This properties file is used to initialize the default +# java.awt.datatransfer.SystemFlavorMap. It contains the X11 platform-specific, +# default mappings between common X11 selection atoms and platform-independent +# MIME type strings, which will be converted into +# java.awt.datatransfer.DataFlavors. +# +# The standard format is: +# +# =,, ... +# +# should be a string identifier that the native platform will +# recognize as a valid data format. should specify both a MIME +# primary type and a MIME subtype separated by a '/'. The MIME type may include +# parameters, where each parameter is a key/value pair separated by '=', and +# where each parameter to the MIME type is separated by a ';'. +# +# Because SystemFlavorMap implements FlavorTable, developers are free to +# duplicate DataFlavor values and set multiple values for a single native by +# separating them with ",". If a mapping contains a duplicate key or value, +# earlier mappings which included this key or value will be preferred. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", and which support the charset parameter, should specify the exact +# format in which the native platform expects the data. The "charset" +# parameter specifies the char to byte encoding, the "eoln" parameter +# specifies the end-of-line marker, and the "terminators" parameter specifies +# the number of terminating NUL bytes. Note that "eoln" and "terminators" +# are not standardized MIME type parameters. They are specific to this file +# format ONLY. They will not appear in any of the DataFlavors returned by the +# SystemFlavorMap at the Java level. +# +# If the "charset" parameter is omitted, or has zero length, the platform +# default encoding is assumed. If the "eoln" parameter is omitted, or has +# zero length, "\n" is assumed. If the "terminators" parameter is omitted, +# or has a value less than zero, zero is assumed. +# +# Upon initialization, the data transfer subsystem will record the specified +# details of the native text format, but the default SystemFlavorMap will +# present a large set of synthesized DataFlavors which map, in both +# directions, to the native. After receiving data from the application in one +# of the synthetic DataFlavors, the data transfer subsystem will transform +# the data stream into the format specified in this file before passing the +# transformed stream to the native system. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", but which do not support the charset parameter, will be treated as +# opaque, 8-bit data. They will not undergo any transformation process, and +# any "charset", "eoln", or "terminators" parameters specified in this file +# will be ignored. +# +# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of +# text flavors which support the charset parameter. + +UTF8_STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 + +# The COMPOUND_TEXT support for inter-client text transfer is disabled by +# default. The reason is that many native applications prefer this format over +# other native text formats, but are unable to decode the textual data in this +# format properly. This results in java-to-native text transfer failures. +# To enable the COMPOUND_TEXT support for this JRE installation uncomment +# the line below. + +# COMPOUND_TEXT=text/plain;charset=x-compound-text;eoln="\n";terminators=0 + +TEXT=text/plain;eoln="\n";terminators=0 +STRING=text/plain;charset=iso8859-1;eoln="\n";terminators=0 +FILE_NAME=application/x-java-file-list;class=java.util.List +text/uri-list=application/x-java-file-list;class=java.util.List +PNG=image/x-java-image;class=java.awt.Image +JFIF=image/x-java-image;class=java.awt.Image --- old/src/java.desktop/windows/classes/sun/datatransfer/resources/flavormap.properties 2015-01-13 17:36:15.770409200 +0400 +++ /dev/null 2015-01-13 17:36:23.000000000 +0400 @@ -1,69 +0,0 @@ -# -# This properties file is used to initialize the default -# java.awt.datatransfer.SystemFlavorMap. It contains the Win32 platform- -# specific, default mappings between common Win32 Clipboard atoms and platform- -# independent MIME type strings, which will be converted into -# java.awt.datatransfer.DataFlavors. -# -# The standard format is: -# -# =,, ... -# -# should be a string identifier that the native platform will -# recognize as a valid data format. should specify both a MIME -# primary type and a MIME subtype separated by a '/'. The MIME type may include -# parameters, where each parameter is a key/value pair separated by '=', and -# where each parameter to the MIME type is separated by a ';'. -# -# Because SystemFlavorMap implements FlavorTable, developers are free to -# duplicate DataFlavor values and set multiple values for a single native by -# separating them with ",". If a mapping contains a duplicate key or value, -# earlier mappings which included this key or value will be preferred.# -# Mappings whose values specify DataFlavors with primary MIME types of -# "text", and which support the charset parameter, should specify the exact -# format in which the native platform expects the data. The "charset" -# parameter specifies the char to byte encoding, the "eoln" parameter -# specifies the end-of-line marker, and the "terminators" parameter specifies -# the number of terminating NUL bytes. Note that "eoln" and "terminators" -# are not standardized MIME type parameters. They are specific to this file -# format ONLY. They will not appear in any of the DataFlavors returned by the -# SystemFlavorMap at the Java level. -# -# If the "charset" parameter is omitted, or has zero length, the platform -# default encoding is assumed. If the "eoln" parameter is omitted, or has -# zero length, "\n" is assumed. If the "terminators" parameter is omitted, -# or has a value less than zero, zero is assumed. -# -# Upon initialization, the data transfer subsystem will record the specified -# details of the native text format, but the default SystemFlavorMap will -# present a large set of synthesized DataFlavors which map, in both -# directions, to the native. After receiving data from the application in one -# of the synthetic DataFlavors, the data transfer subsystem will transform -# the data stream into the format specified in this file before passing the -# transformed stream to the native system. -# -# Mappings whose values specify DataFlavors with primary MIME types of -# "text", but which do not support the charset parameter, will be treated as -# opaque, 8-bit data. They will not undergo any transformation process, and -# any "charset", "eoln", or "terminators" parameters specified in this file -# will be ignored. -# -# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of -# text flavors which support the charset parameter. - -UNICODE\ TEXT=text/plain;charset=utf-16le;eoln="\r\n";terminators=2 -TEXT=text/plain;eoln="\r\n";terminators=1 -HTML\ Format=text/html;charset=utf-8;eoln="\r\n";terminators=1 -Rich\ Text\ Format=text/rtf -HDROP=application/x-java-file-list;class=java.util.List -PNG=image/x-java-image;class=java.awt.Image -JFIF=image/x-java-image;class=java.awt.Image -DIB=image/x-java-image;class=java.awt.Image -ENHMETAFILE=image/x-java-image;class=java.awt.Image -METAFILEPICT=image/x-java-image;class=java.awt.Image -LOCALE=application/x-java-text-encoding;class="[B" -UniformResourceLocator=application/x-java-url;class=java.net.URL,\ - text/uri-list;eoln="\r\n";terminators=1,\ - text/plain;eoln="\r\n";terminators=1 -FileGroupDescriptorW=application/x-java-file-list;class=java.util.List -FileGroupDescriptor=application/x-java-file-list;class=java.util.List --- /dev/null 2015-01-13 17:36:25.000000000 +0400 +++ new/src/java.datatransfer/windows/classes/sun/datatransfer/resources/flavormap.properties 2015-01-13 17:36:14.621343500 +0400 @@ -0,0 +1,69 @@ +# +# This properties file is used to initialize the default +# java.awt.datatransfer.SystemFlavorMap. It contains the Win32 platform- +# specific, default mappings between common Win32 Clipboard atoms and platform- +# independent MIME type strings, which will be converted into +# java.awt.datatransfer.DataFlavors. +# +# The standard format is: +# +# =,, ... +# +# should be a string identifier that the native platform will +# recognize as a valid data format. should specify both a MIME +# primary type and a MIME subtype separated by a '/'. The MIME type may include +# parameters, where each parameter is a key/value pair separated by '=', and +# where each parameter to the MIME type is separated by a ';'. +# +# Because SystemFlavorMap implements FlavorTable, developers are free to +# duplicate DataFlavor values and set multiple values for a single native by +# separating them with ",". If a mapping contains a duplicate key or value, +# earlier mappings which included this key or value will be preferred.# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", and which support the charset parameter, should specify the exact +# format in which the native platform expects the data. The "charset" +# parameter specifies the char to byte encoding, the "eoln" parameter +# specifies the end-of-line marker, and the "terminators" parameter specifies +# the number of terminating NUL bytes. Note that "eoln" and "terminators" +# are not standardized MIME type parameters. They are specific to this file +# format ONLY. They will not appear in any of the DataFlavors returned by the +# SystemFlavorMap at the Java level. +# +# If the "charset" parameter is omitted, or has zero length, the platform +# default encoding is assumed. If the "eoln" parameter is omitted, or has +# zero length, "\n" is assumed. If the "terminators" parameter is omitted, +# or has a value less than zero, zero is assumed. +# +# Upon initialization, the data transfer subsystem will record the specified +# details of the native text format, but the default SystemFlavorMap will +# present a large set of synthesized DataFlavors which map, in both +# directions, to the native. After receiving data from the application in one +# of the synthetic DataFlavors, the data transfer subsystem will transform +# the data stream into the format specified in this file before passing the +# transformed stream to the native system. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", but which do not support the charset parameter, will be treated as +# opaque, 8-bit data. They will not undergo any transformation process, and +# any "charset", "eoln", or "terminators" parameters specified in this file +# will be ignored. +# +# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of +# text flavors which support the charset parameter. + +UNICODE\ TEXT=text/plain;charset=utf-16le;eoln="\r\n";terminators=2 +TEXT=text/plain;eoln="\r\n";terminators=1 +HTML\ Format=text/html;charset=utf-8;eoln="\r\n";terminators=1 +Rich\ Text\ Format=text/rtf +HDROP=application/x-java-file-list;class=java.util.List +PNG=image/x-java-image;class=java.awt.Image +JFIF=image/x-java-image;class=java.awt.Image +DIB=image/x-java-image;class=java.awt.Image +ENHMETAFILE=image/x-java-image;class=java.awt.Image +METAFILEPICT=image/x-java-image;class=java.awt.Image +LOCALE=application/x-java-text-encoding;class="[B" +UniformResourceLocator=application/x-java-url;class=java.net.URL,\ + text/uri-list;eoln="\r\n";terminators=1,\ + text/plain;eoln="\r\n";terminators=1 +FileGroupDescriptorW=application/x-java-file-list;class=java.util.List +FileGroupDescriptor=application/x-java-file-list;class=java.util.List