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

Print this page




  40 import java.io.ByteArrayInputStream;
  41 import java.io.ByteArrayOutputStream;
  42 import java.io.File;
  43 import java.io.InputStream;
  44 import java.io.InputStreamReader;
  45 import java.io.IOException;
  46 import java.io.ObjectInputStream;
  47 import java.io.ObjectOutputStream;
  48 import java.io.Reader;
  49 import java.io.SequenceInputStream;
  50 import java.io.StringReader;
  51 
  52 import java.net.URI;
  53 import java.net.URISyntaxException;
  54 
  55 import java.nio.ByteBuffer;
  56 import java.nio.CharBuffer;
  57 import java.nio.charset.Charset;
  58 import java.nio.charset.CharsetEncoder;
  59 import java.nio.charset.IllegalCharsetNameException;

  60 import java.nio.charset.UnsupportedCharsetException;
  61 
  62 import java.lang.reflect.Constructor;
  63 import java.lang.reflect.InvocationTargetException;
  64 import java.lang.reflect.Method;
  65 import java.lang.reflect.Modifier;
  66 
  67 import java.security.AccessController;
  68 import java.security.PrivilegedAction;
  69 import java.security.PrivilegedActionException;
  70 import java.security.PrivilegedExceptionAction;
  71 import java.security.ProtectionDomain;
  72 
  73 import java.util.AbstractMap;
  74 import java.util.ArrayList;
  75 import java.util.Arrays;
  76 import java.util.Collections;
  77 import java.util.Comparator;
  78 import java.util.HashMap;
  79 import java.util.HashSet;


 147      * </pre>
 148      */
 149     public static final DataFlavor javaTextEncodingFlavor;
 150 
 151     /**
 152      * Lazy initialization of Standard Encodings.
 153      */
 154     private static class StandardEncodingsHolder {
 155         private static final SortedSet<String> standardEncodings = load();
 156 
 157         private static SortedSet<String> load() {
 158             final Comparator<String> comparator =
 159                     new CharsetComparator(IndexedComparator.SELECT_WORST);
 160             final SortedSet<String> tempSet = new TreeSet<>(comparator);
 161             tempSet.add("US-ASCII");
 162             tempSet.add("ISO-8859-1");
 163             tempSet.add("UTF-8");
 164             tempSet.add("UTF-16BE");
 165             tempSet.add("UTF-16LE");
 166             tempSet.add("UTF-16");
 167             tempSet.add(getDefaultTextCharset());
 168             return Collections.unmodifiableSortedSet(tempSet);
 169         }
 170     }
 171 
 172     /**
 173      * Tracks whether a particular text/* MIME type supports the charset
 174      * parameter. The Map is initialized with all of the standard MIME types
 175      * listed in the DataFlavor.selectBestTextFlavor method comment. Additional
 176      * entries may be added during the life of the JRE for text/<other> types.
 177      */
 178     private static final Map<String, Boolean> textMIMESubtypeCharsetSupport;
 179 
 180     /**
 181      * Cache of the platform default encoding as specified in the
 182      * "file.encoding" system property.
 183      */
 184     private static String defaultEncoding;
 185 
 186     /**
 187      * A collection of all natives listed in flavormap.properties with
 188      * a primary MIME type of "text".
 189      */
 190     private static final Set<Long> textNatives =
 191             Collections.synchronizedSet(new HashSet<>());
 192 
 193     /**
 194      * The native encodings/charsets for the Set of textNatives.
 195      */
 196     private static final Map<Long, String> nativeCharsets =
 197             Collections.synchronizedMap(new HashMap<>());
 198 
 199     /**
 200      * The end-of-line markers for the Set of textNatives.
 201      */
 202     private static final Map<Long, String> nativeEOLNs =
 203             Collections.synchronizedMap(new HashMap<>());
 204 
 205     /**
 206      * The number of terminating NUL bytes for the Set of textNatives.


 264             return encoding;
 265         } catch (UnsupportedCharsetException uce) {
 266             return encoding;
 267         }
 268     }
 269 
 270     /**
 271      * If the specified flavor is a text flavor which supports the "charset"
 272      * parameter, then this method returns that parameter, or the default
 273      * charset if no such parameter was specified at construction. For non-
 274      * text DataFlavors, and for non-charset text flavors, this method returns
 275      * null.
 276      */
 277     public static String getTextCharset(DataFlavor flavor) {
 278         if (!isFlavorCharsetTextType(flavor)) {
 279             return null;
 280         }
 281 
 282         String encoding = flavor.getParameter("charset");
 283 
 284         return (encoding != null) ? encoding : getDefaultTextCharset();
 285     }
 286 
 287     /**
 288      * Returns the platform's default character encoding.
 289      */
 290     public static String getDefaultTextCharset() {
 291         if (defaultEncoding != null) {
 292             return defaultEncoding;
 293         }
 294         return defaultEncoding = Charset.defaultCharset().name();
 295     }
 296 
 297     /**
 298      * Tests only whether the flavor's MIME type supports the charset
 299      * parameter. Must only be called for flavors with a primary type of
 300      * "text".
 301      */
 302     public static boolean doesSubtypeSupportCharset(DataFlavor flavor) {
 303         if (dtLog.isLoggable(PlatformLogger.Level.FINE)) {
 304             if (!"text".equals(flavor.getPrimaryType())) {
 305                 dtLog.fine("Assertion (\"text\".equals(flavor.getPrimaryType())) failed");
 306             }
 307         }
 308 
 309         String subType = flavor.getSubType();
 310         if (subType == null) {
 311             return false;
 312         }
 313 
 314         Boolean support = textMIMESubtypeCharsetSupport.get(subType);


 468 
 469     /**
 470      * Returns the default Unicode encoding for the platform. The encoding
 471      * need not be canonical. This method is only used by the archaic function
 472      * DataFlavor.getTextPlainUnicodeFlavor().
 473      */
 474     public abstract String getDefaultUnicodeEncoding();
 475 
 476     /**
 477      * This method is called for text flavor mappings established while parsing
 478      * the flavormap.properties file. It stores the "eoln" and "terminators"
 479      * parameters which are not officially part of the MIME type. They are
 480      * MIME parameters specific to the flavormap.properties file format.
 481      */
 482     public void registerTextFlavorProperties(String nat, String charset,
 483                                              String eoln, String terminators) {
 484         Long format = getFormatForNativeAsLong(nat);
 485 
 486         textNatives.add(format);
 487         nativeCharsets.put(format, (charset != null && charset.length() != 0)
 488                 ? charset : getDefaultTextCharset());
 489         if (eoln != null && eoln.length() != 0 && !eoln.equals("\n")) {
 490             nativeEOLNs.put(format, eoln);
 491         }
 492         if (terminators != null && terminators.length() != 0) {
 493             Integer iTerminators = Integer.valueOf(terminators);
 494             if (iTerminators > 0) {
 495                 nativeTerminators.put(format, iTerminators);
 496             }
 497         }
 498     }
 499 
 500     /**
 501      * Determines whether the native corresponding to the specified long format
 502      * was listed in the flavormap.properties file.
 503      */
 504     protected boolean isTextFormat(long format) {
 505         return textNatives.contains(Long.valueOf(format));
 506     }
 507 
 508     protected String getCharsetForTextFormat(Long lFormat) {


 769         // getFlavorsForFormats().
 770         return setToSortedDataFlavorArray(getFlavorsForFormatsAsSet(formats, map));
 771     }
 772 
 773     /**
 774      * Looks-up or registers the String native with the native data transfer
 775      * system and returns a long format corresponding to that native.
 776      */
 777     protected abstract Long getFormatForNativeAsLong(String str);
 778 
 779     /**
 780      * Looks-up the String native corresponding to the specified long format in
 781      * the native data transfer system.
 782      */
 783     protected abstract String getNativeForFormat(long format);
 784 
 785     /* Contains common code for finding the best charset for
 786      * clipboard string encoding/decoding, basing on clipboard
 787      * format and localeTransferable(on decoding, if available)
 788      */
 789     private String getBestCharsetForTextFormat(Long lFormat,
 790         Transferable localeTransferable) throws IOException
 791     {
 792         String charset = null;
 793         if (localeTransferable != null &&
 794             isLocaleDependentTextFormat(lFormat) &&
 795             localeTransferable.isDataFlavorSupported(javaTextEncodingFlavor))
 796         {
 797             try {
 798                 charset = new String(
 799                     (byte[])localeTransferable.getTransferData(javaTextEncodingFlavor),
 800                     "UTF-8"
 801                 );
 802             } catch (UnsupportedFlavorException cannotHappen) {
 803             }
 804         } else {
 805             charset = getCharsetForTextFormat(lFormat);
 806         }
 807         if (charset == null) {
 808             // Only happens when we have a custom text type.
 809             charset = getDefaultTextCharset();
 810         }
 811         return charset;
 812     }
 813 
 814     /**
 815      *  Translation function for converting string into
 816      *  a byte array. Search-and-replace EOLN. Encode into the
 817      *  target format. Append terminating NUL bytes.
 818      *
 819      *  Java to Native string conversion
 820      */
 821     private byte[] translateTransferableString(String str,
 822                                                long format) throws IOException
 823     {
 824         Long lFormat = format;
 825         String charset = getBestCharsetForTextFormat(lFormat, null);
 826         // Search and replace EOLN. Note that if EOLN is "\n", then we
 827         // never added an entry to nativeEOLNs anyway, so we'll skip this
 828         // code altogether.
 829         // windows: "abc\nde"->"abc\r\nde"


1714         final char[] in = new char[2];
1715         byte[] out;
1716 
1717         CharsetEncoder encoder;
1718         CharBuffer inBuf;
1719         ByteBuffer outBuf;
1720 
1721         char[] eoln;
1722         int numTerminators;
1723 
1724         boolean eos;
1725         int index, limit;
1726 
1727         public ReencodingInputStream(InputStream bytestream, long format,
1728                                      String targetEncoding,
1729                                      Transferable localeTransferable)
1730             throws IOException
1731         {
1732             Long lFormat = format;
1733 
1734             String sourceEncoding = null;
1735             if (isLocaleDependentTextFormat(format) &&
1736                 localeTransferable != null &&
1737                 localeTransferable.
1738                     isDataFlavorSupported(javaTextEncodingFlavor))
1739             {
1740                 try {
1741                     sourceEncoding = new String((byte[])localeTransferable.
1742                                        getTransferData(javaTextEncodingFlavor),
1743                                        "UTF-8");
1744                 } catch (UnsupportedFlavorException cannotHappen) {
1745                 }
1746             } else {
1747                 sourceEncoding = getCharsetForTextFormat(lFormat);
1748             }
1749 
1750             if (sourceEncoding == null) {
1751                 // Only happens when we have a custom text type.
1752                 sourceEncoding = getDefaultTextCharset();
1753             }
1754             wrapped = new BufferedReader
1755                 (new InputStreamReader(bytestream, sourceEncoding));
1756 
1757             if (targetEncoding == null) {
1758                 // Throw NullPointerException for compatibility with the former
1759                 // call to sun.io.CharToByteConverter.getConverter(null)
1760                 // (Charset.forName(null) throws unspecified IllegalArgumentException
1761                 // now; see 6228568)
1762                 throw new NullPointerException("null target encoding");
1763             }
1764 
1765             try {
1766                 encoder = Charset.forName(targetEncoding).newEncoder();
1767                 out = new byte[(int)(encoder.maxBytesPerChar() * 2 + 0.5)];
1768                 inBuf = CharBuffer.wrap(in);
1769                 outBuf = ByteBuffer.wrap(out);
1770             } catch (IllegalCharsetNameException
1771                     | UnsupportedCharsetException
1772                     | UnsupportedOperationException e) {
1773                 throw new IOException(e.toString());
1774             }
1775 


2316          *             index than the second.
2317          */
2318         static <T> int compareIndices(Map<T, Integer> indexMap,
2319                                       T obj1, T obj2,
2320                                       Integer fallbackIndex) {
2321             Integer index1 = indexMap.getOrDefault(obj1, fallbackIndex);
2322             Integer index2 = indexMap.getOrDefault(obj2, fallbackIndex);
2323             return index1.compareTo(index2);
2324         }
2325     }
2326 
2327     /**
2328      * An IndexedComparator which compares two String charsets. The comparison
2329      * follows the rules outlined in DataFlavor.selectBestTextFlavor. In order
2330      * to ensure that non-Unicode, non-ASCII, non-default charsets are sorted
2331      * in alphabetical order, charsets are not automatically converted to their
2332      * canonical forms.
2333      */
2334     public static class CharsetComparator extends IndexedComparator<String> {
2335         private static final Map<String, Integer> charsets;
2336         private static final String defaultEncoding;
2337 
2338         private static final Integer DEFAULT_CHARSET_INDEX = 2;
2339         private static final Integer OTHER_CHARSET_INDEX = 1;
2340         private static final Integer WORST_CHARSET_INDEX = 0;
2341         private static final Integer UNSUPPORTED_CHARSET_INDEX = Integer.MIN_VALUE;
2342 
2343         private static final String UNSUPPORTED_CHARSET = "UNSUPPORTED";
2344 
2345         static {
2346             Map<String, Integer> charsetsMap = new HashMap<>(8, 1.0f);
2347 
2348             // we prefer Unicode charsets
2349             charsetsMap.put(canonicalName("UTF-16LE"), 4);
2350             charsetsMap.put(canonicalName("UTF-16BE"), 5);
2351             charsetsMap.put(canonicalName("UTF-8"), 6);
2352             charsetsMap.put(canonicalName("UTF-16"), 7);
2353 
2354             // US-ASCII is the worst charset supported
2355             charsetsMap.put(canonicalName("US-ASCII"), WORST_CHARSET_INDEX);
2356 
2357             defaultEncoding = DataTransferer.canonicalName(DataTransferer.getDefaultTextCharset());
2358             charsetsMap.putIfAbsent(defaultEncoding, DEFAULT_CHARSET_INDEX);
2359 
2360             charsetsMap.put(UNSUPPORTED_CHARSET, UNSUPPORTED_CHARSET_INDEX);
2361 
2362             charsets = Collections.unmodifiableMap(charsetsMap);
2363         }
2364 
2365         public CharsetComparator(boolean order) {
2366             super(order);
2367         }
2368 
2369         /**
2370          * Compares two String objects. Returns a negative integer, zero,
2371          * or a positive integer as the first charset is worse than, equal to,
2372          * or better than the second.
2373          *
2374          * @param obj1 the first charset to be compared
2375          * @param obj2 the second charset to be compared
2376          * @return a negative integer, zero, or a positive integer as the
2377          *         first argument is worse, equal to, or better than the
2378          *         second.




  40 import java.io.ByteArrayInputStream;
  41 import java.io.ByteArrayOutputStream;
  42 import java.io.File;
  43 import java.io.InputStream;
  44 import java.io.InputStreamReader;
  45 import java.io.IOException;
  46 import java.io.ObjectInputStream;
  47 import java.io.ObjectOutputStream;
  48 import java.io.Reader;
  49 import java.io.SequenceInputStream;
  50 import java.io.StringReader;
  51 
  52 import java.net.URI;
  53 import java.net.URISyntaxException;
  54 
  55 import java.nio.ByteBuffer;
  56 import java.nio.CharBuffer;
  57 import java.nio.charset.Charset;
  58 import java.nio.charset.CharsetEncoder;
  59 import java.nio.charset.IllegalCharsetNameException;
  60 import java.nio.charset.StandardCharsets;
  61 import java.nio.charset.UnsupportedCharsetException;
  62 
  63 import java.lang.reflect.Constructor;
  64 import java.lang.reflect.InvocationTargetException;
  65 import java.lang.reflect.Method;
  66 import java.lang.reflect.Modifier;
  67 
  68 import java.security.AccessController;
  69 import java.security.PrivilegedAction;
  70 import java.security.PrivilegedActionException;
  71 import java.security.PrivilegedExceptionAction;
  72 import java.security.ProtectionDomain;
  73 
  74 import java.util.AbstractMap;
  75 import java.util.ArrayList;
  76 import java.util.Arrays;
  77 import java.util.Collections;
  78 import java.util.Comparator;
  79 import java.util.HashMap;
  80 import java.util.HashSet;


 148      * </pre>
 149      */
 150     public static final DataFlavor javaTextEncodingFlavor;
 151 
 152     /**
 153      * Lazy initialization of Standard Encodings.
 154      */
 155     private static class StandardEncodingsHolder {
 156         private static final SortedSet<String> standardEncodings = load();
 157 
 158         private static SortedSet<String> load() {
 159             final Comparator<String> comparator =
 160                     new CharsetComparator(IndexedComparator.SELECT_WORST);
 161             final SortedSet<String> tempSet = new TreeSet<>(comparator);
 162             tempSet.add("US-ASCII");
 163             tempSet.add("ISO-8859-1");
 164             tempSet.add("UTF-8");
 165             tempSet.add("UTF-16BE");
 166             tempSet.add("UTF-16LE");
 167             tempSet.add("UTF-16");
 168             tempSet.add(Charset.defaultCharset().name());
 169             return Collections.unmodifiableSortedSet(tempSet);
 170         }
 171     }
 172 
 173     /**
 174      * Tracks whether a particular text/* MIME type supports the charset
 175      * parameter. The Map is initialized with all of the standard MIME types
 176      * listed in the DataFlavor.selectBestTextFlavor method comment. Additional
 177      * entries may be added during the life of the JRE for text/<other> types.
 178      */
 179     private static final Map<String, Boolean> textMIMESubtypeCharsetSupport;
 180 
 181     /**






 182      * A collection of all natives listed in flavormap.properties with
 183      * a primary MIME type of "text".
 184      */
 185     private static final Set<Long> textNatives =
 186             Collections.synchronizedSet(new HashSet<>());
 187 
 188     /**
 189      * The native encodings/charsets for the Set of textNatives.
 190      */
 191     private static final Map<Long, String> nativeCharsets =
 192             Collections.synchronizedMap(new HashMap<>());
 193 
 194     /**
 195      * The end-of-line markers for the Set of textNatives.
 196      */
 197     private static final Map<Long, String> nativeEOLNs =
 198             Collections.synchronizedMap(new HashMap<>());
 199 
 200     /**
 201      * The number of terminating NUL bytes for the Set of textNatives.


 259             return encoding;
 260         } catch (UnsupportedCharsetException uce) {
 261             return encoding;
 262         }
 263     }
 264 
 265     /**
 266      * If the specified flavor is a text flavor which supports the "charset"
 267      * parameter, then this method returns that parameter, or the default
 268      * charset if no such parameter was specified at construction. For non-
 269      * text DataFlavors, and for non-charset text flavors, this method returns
 270      * null.
 271      */
 272     public static String getTextCharset(DataFlavor flavor) {
 273         if (!isFlavorCharsetTextType(flavor)) {
 274             return null;
 275         }
 276 
 277         String encoding = flavor.getParameter("charset");
 278 
 279         return (encoding != null) ? encoding : Charset.defaultCharset().name();










 280     }
 281 
 282     /**
 283      * Tests only whether the flavor's MIME type supports the charset
 284      * parameter. Must only be called for flavors with a primary type of
 285      * "text".
 286      */
 287     public static boolean doesSubtypeSupportCharset(DataFlavor flavor) {
 288         if (dtLog.isLoggable(PlatformLogger.Level.FINE)) {
 289             if (!"text".equals(flavor.getPrimaryType())) {
 290                 dtLog.fine("Assertion (\"text\".equals(flavor.getPrimaryType())) failed");
 291             }
 292         }
 293 
 294         String subType = flavor.getSubType();
 295         if (subType == null) {
 296             return false;
 297         }
 298 
 299         Boolean support = textMIMESubtypeCharsetSupport.get(subType);


 453 
 454     /**
 455      * Returns the default Unicode encoding for the platform. The encoding
 456      * need not be canonical. This method is only used by the archaic function
 457      * DataFlavor.getTextPlainUnicodeFlavor().
 458      */
 459     public abstract String getDefaultUnicodeEncoding();
 460 
 461     /**
 462      * This method is called for text flavor mappings established while parsing
 463      * the flavormap.properties file. It stores the "eoln" and "terminators"
 464      * parameters which are not officially part of the MIME type. They are
 465      * MIME parameters specific to the flavormap.properties file format.
 466      */
 467     public void registerTextFlavorProperties(String nat, String charset,
 468                                              String eoln, String terminators) {
 469         Long format = getFormatForNativeAsLong(nat);
 470 
 471         textNatives.add(format);
 472         nativeCharsets.put(format, (charset != null && charset.length() != 0)
 473                 ? charset : Charset.defaultCharset().name());
 474         if (eoln != null && eoln.length() != 0 && !eoln.equals("\n")) {
 475             nativeEOLNs.put(format, eoln);
 476         }
 477         if (terminators != null && terminators.length() != 0) {
 478             Integer iTerminators = Integer.valueOf(terminators);
 479             if (iTerminators > 0) {
 480                 nativeTerminators.put(format, iTerminators);
 481             }
 482         }
 483     }
 484 
 485     /**
 486      * Determines whether the native corresponding to the specified long format
 487      * was listed in the flavormap.properties file.
 488      */
 489     protected boolean isTextFormat(long format) {
 490         return textNatives.contains(Long.valueOf(format));
 491     }
 492 
 493     protected String getCharsetForTextFormat(Long lFormat) {


 754         // getFlavorsForFormats().
 755         return setToSortedDataFlavorArray(getFlavorsForFormatsAsSet(formats, map));
 756     }
 757 
 758     /**
 759      * Looks-up or registers the String native with the native data transfer
 760      * system and returns a long format corresponding to that native.
 761      */
 762     protected abstract Long getFormatForNativeAsLong(String str);
 763 
 764     /**
 765      * Looks-up the String native corresponding to the specified long format in
 766      * the native data transfer system.
 767      */
 768     protected abstract String getNativeForFormat(long format);
 769 
 770     /* Contains common code for finding the best charset for
 771      * clipboard string encoding/decoding, basing on clipboard
 772      * format and localeTransferable(on decoding, if available)
 773      */
 774     protected String getBestCharsetForTextFormat(Long lFormat,
 775         Transferable localeTransferable) throws IOException
 776     {
 777         String charset = null;
 778         if (localeTransferable != null &&
 779             isLocaleDependentTextFormat(lFormat) &&
 780             localeTransferable.isDataFlavorSupported(javaTextEncodingFlavor)) {

 781             try {
 782                 byte[] charsetNameBytes = (byte[])localeTransferable.getTransferData(javaTextEncodingFlavor);
 783                 charset = new String(charsetNameBytes, StandardCharsets.UTF_8);


 784             } catch (UnsupportedFlavorException cannotHappen) {
 785             }
 786         } else {
 787             charset = getCharsetForTextFormat(lFormat);
 788         }
 789         if (charset == null) {
 790             // Only happens when we have a custom text type.
 791             charset = Charset.defaultCharset().name();
 792         }
 793         return charset;
 794     }
 795 
 796     /**
 797      *  Translation function for converting string into
 798      *  a byte array. Search-and-replace EOLN. Encode into the
 799      *  target format. Append terminating NUL bytes.
 800      *
 801      *  Java to Native string conversion
 802      */
 803     private byte[] translateTransferableString(String str,
 804                                                long format) throws IOException
 805     {
 806         Long lFormat = format;
 807         String charset = getBestCharsetForTextFormat(lFormat, null);
 808         // Search and replace EOLN. Note that if EOLN is "\n", then we
 809         // never added an entry to nativeEOLNs anyway, so we'll skip this
 810         // code altogether.
 811         // windows: "abc\nde"->"abc\r\nde"


1696         final char[] in = new char[2];
1697         byte[] out;
1698 
1699         CharsetEncoder encoder;
1700         CharBuffer inBuf;
1701         ByteBuffer outBuf;
1702 
1703         char[] eoln;
1704         int numTerminators;
1705 
1706         boolean eos;
1707         int index, limit;
1708 
1709         public ReencodingInputStream(InputStream bytestream, long format,
1710                                      String targetEncoding,
1711                                      Transferable localeTransferable)
1712             throws IOException
1713         {
1714             Long lFormat = format;
1715 
1716             String sourceEncoding = getBestCharsetForTextFormat(format, localeTransferable);
1717             wrapped = new BufferedReader(new InputStreamReader(bytestream, sourceEncoding));




















1718 
1719             if (targetEncoding == null) {
1720                 // Throw NullPointerException for compatibility with the former
1721                 // call to sun.io.CharToByteConverter.getConverter(null)
1722                 // (Charset.forName(null) throws unspecified IllegalArgumentException
1723                 // now; see 6228568)
1724                 throw new NullPointerException("null target encoding");
1725             }
1726 
1727             try {
1728                 encoder = Charset.forName(targetEncoding).newEncoder();
1729                 out = new byte[(int)(encoder.maxBytesPerChar() * 2 + 0.5)];
1730                 inBuf = CharBuffer.wrap(in);
1731                 outBuf = ByteBuffer.wrap(out);
1732             } catch (IllegalCharsetNameException
1733                     | UnsupportedCharsetException
1734                     | UnsupportedOperationException e) {
1735                 throw new IOException(e.toString());
1736             }
1737 


2278          *             index than the second.
2279          */
2280         static <T> int compareIndices(Map<T, Integer> indexMap,
2281                                       T obj1, T obj2,
2282                                       Integer fallbackIndex) {
2283             Integer index1 = indexMap.getOrDefault(obj1, fallbackIndex);
2284             Integer index2 = indexMap.getOrDefault(obj2, fallbackIndex);
2285             return index1.compareTo(index2);
2286         }
2287     }
2288 
2289     /**
2290      * An IndexedComparator which compares two String charsets. The comparison
2291      * follows the rules outlined in DataFlavor.selectBestTextFlavor. In order
2292      * to ensure that non-Unicode, non-ASCII, non-default charsets are sorted
2293      * in alphabetical order, charsets are not automatically converted to their
2294      * canonical forms.
2295      */
2296     public static class CharsetComparator extends IndexedComparator<String> {
2297         private static final Map<String, Integer> charsets;

2298 
2299         private static final Integer DEFAULT_CHARSET_INDEX = 2;
2300         private static final Integer OTHER_CHARSET_INDEX = 1;
2301         private static final Integer WORST_CHARSET_INDEX = 0;
2302         private static final Integer UNSUPPORTED_CHARSET_INDEX = Integer.MIN_VALUE;
2303 
2304         private static final String UNSUPPORTED_CHARSET = "UNSUPPORTED";
2305 
2306         static {
2307             Map<String, Integer> charsetsMap = new HashMap<>(8, 1.0f);
2308 
2309             // we prefer Unicode charsets
2310             charsetsMap.put(canonicalName("UTF-16LE"), 4);
2311             charsetsMap.put(canonicalName("UTF-16BE"), 5);
2312             charsetsMap.put(canonicalName("UTF-8"), 6);
2313             charsetsMap.put(canonicalName("UTF-16"), 7);
2314 
2315             // US-ASCII is the worst charset supported
2316             charsetsMap.put(canonicalName("US-ASCII"), WORST_CHARSET_INDEX);
2317 
2318             charsetsMap.putIfAbsent(Charset.defaultCharset().name(), DEFAULT_CHARSET_INDEX);

2319 
2320             charsetsMap.put(UNSUPPORTED_CHARSET, UNSUPPORTED_CHARSET_INDEX);
2321 
2322             charsets = Collections.unmodifiableMap(charsetsMap);
2323         }
2324 
2325         public CharsetComparator(boolean order) {
2326             super(order);
2327         }
2328 
2329         /**
2330          * Compares two String objects. Returns a negative integer, zero,
2331          * or a positive integer as the first charset is worse than, equal to,
2332          * or better than the second.
2333          *
2334          * @param obj1 the first charset to be compared
2335          * @param obj2 the second charset to be compared
2336          * @return a negative integer, zero, or a positive integer as the
2337          *         first argument is worse, equal to, or better than the
2338          *         second.